先康康概念~
能否使用动态规划,我认为最主要取决于该问题能否被分解为小问题并且会不会被重复调用。
举个例子,有n个阶梯,一个人每一步只能跨一个台阶或者两个,问这个人一共有多少种走法?
令n=10,可以转化为如图所示:
那么我们如果已经计算出来5-10的路径数,我们是否要将此路径数保存下来?
yes!因为此信息等会都要被用到!不管是从3、4过来的,到5之后,存在的路径就是第一次的结果!所以也就是可以用到动态规划的方法解决。
1创建一个数组a[],专门用于存放位点x-10的所有可能路径数,初始值为0,每次计算x-10的路径数时,要检测路径是否大于0,如果大于0,则说明他已经被计算过并存于a[x]中
得到递推结果 a[x]=a[x+1]+a[x+2] a[6]=a[7]+a[8] a[7]=a[8]+a[9] 发现计算a[6] a[7]的时候,我们都用了a[8],重复利用结果。
进入正题
打家劫舍
打家劫舍
你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。
示例 1:
输入:[1,2,3,1]
输出:4
解释:偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。
偷窃到的最高金额 = 1 + 3 = 4 。
示例 2:
输入:[2,7,9,3,1]
输出:12
解释:偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9),接着偷窃 5 号房屋 (金额 = 1)。
偷窃到的最高金额 = 2 + 9 + 1 = 12 。
提示:
1 <= nums.length <= 100
0 <= nums[i] <= 400
此问题与前面爬楼梯类似,假如我们知道了i-3~i家偷的金额,那么我们从第0家开始算的时候,同样需要用到i-3~i的数据,那么解决问题的关键就是找到递归公式
本题有两个变量:一个是偷到第几家了?一个是偷没偷?
这里可以定义一个二维数组dp[length][2],其中dp[i][0]表示第i+1(因为数组下标是从0开始的,所以这里是i+1)家偷了的最大总金额,dp[i][1]表示的是第i+1家没偷的最大总金额。那么我们找出递推公式
1,dp[i][0]=max(dp[i-1][0],dp[i-1][1])
他表示如果第i+1家没偷,那么第i家有没有偷都是可以的,我们取最大值即可。
2,dp[i][1]=dp[i-1][0]+nums[i]
他表示的是如果第i+1家偷了,那么第i家必须没偷,这里nums[i]表示的是第i+1家偷的金额。
递推公式找出来之后我们再来看下边界条件,第一家可以选择偷,也可以选择不偷,所以
dp[0][0]=0,第一家没偷
dp[0][1]=nums[0],第一家偷了
最后再来看下代码
public int rob(int[] nums) {
//边界条件判断
if (nums == null || nums.length == 0)
return 0;
int length = nums.length;
int[][] dp = new int[length][2];
dp[0][0] = 0;//第1家没偷
dp[0][1] = nums[0];//第1家偷了
//从第2个开始判断
for (int i = 1; i < length; i++) {
//下面两行是递推公式
dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1]);
dp[i][1] = dp[i - 1][0] + nums[i];
}
//最后取最大值即可
return Math.max(dp[length - 1][0], dp[length - 1][1]);
}