剑指 Offer II 089. 房屋偷盗(198. 打家劫舍)
题目:
思路:
【0】这道题吧,怎么说,算是大学了解动态规划入门的一道题吧。思路和跳台阶很像,因为当位置为N的时候,情况可以分为两种,就是N的位置选和不选,选的话,那么根据最大值的原理,必然是F(N)= x + F(N-2) ,x为N位置的值。如果不选,那么必然是因为F(N-1)> x + F(N-2) ,所以基于最大值的理论,应该F(N)= F(N-1),故可以理解为 F(N) = Math.max(F(N-1), X + F(N-2)) , 这种可以直接是到第三个数开始,不然其实就只能从第一个数和第二个数中进行二选一。
【1】动态规划的方式
代码展示:
动态规划的方式:
//时间0 ms击败100% //内存38.8 MB击败71.94% //时间复杂度 O(n) //空间复杂度 O(n) class Solution { public int rob(int[] nums) { if (nums.length == 0) return 0; int n = nums.length; int[] dp = new int[n+1]; dp[0] = 0; dp[1] = nums[0]; for (int k = 2; k <= n; k++) { dp[k] = Math.max(dp[k-1], nums[k-1] + dp[k-2]); } return dp[n]; } } //优化空间复杂度 //时间0 ms击败100% //内存38.9 MB击败51.34% //时间复杂度 O(n) //空间复杂度 O(1) //先说说为什么能简化吧,首先要求的是最大值,所以也就是说,不同位置的最大数其实不重要 //其次这个的函数有点像是跳台阶那道题,所以计算当前N位置的值,需要的是知道N-1和N-2的最大值即可,那么基于这样就不用了创建数组了,直接用常量即可 class Solution { public int rob(int[] nums) { int prev = 0; int curr = 0; // 每次循环,计算“偷到当前房子为止的最大金额” for (int i : nums) { // 循环开始时,curr 表示 dp[k-1],prev 表示 dp[k-2] // dp[k] = max{ dp[k-1], dp[k-2] + i } int temp = Math.max(curr, prev + i); prev = curr; curr = temp; // 循环结束时,curr 表示 dp[k],prev 表示 dp[k-1] } return curr; } }
//时间0 ms击败100%//内存38.8 MB击败71.94%//时间复杂度 O(n)//空间复杂度 O(n)class Solution { public int rob(int[] nums) { if (nums.length == 0) return 0;
int n = nums.length; int[] dp = new int[n+1]; dp[0] = 0; dp[1] = nums[0]; for (int k = 2; k <= n; k++) { dp[k] = Math.max(dp[k-1], nums[k-1] + dp[k-2]); } return dp[n]; }}
//优化空间复杂度//时间0 ms击败100%//内存38.9 MB击败51.34%//时间复杂度 O(n)//空间复杂度 O(1)//先说说为什么能简化吧,首先要求的是最大值,所以也就是说,不同位置的最大数其实不重要//其次这个的函数有点像是跳台阶那道题,所以计算当前N位置的值,需要的是知道N-1和N-2的最大值即可,那么基于这样就不用了创建数组了,直接用常量即可class Solution { public int rob(int[] nums) { int prev = 0; int curr = 0;
// 每次循环,计算“偷到当前房子为止的最大金额” for (int i : nums) { // 循环开始时,curr 表示 dp[k-1],prev 表示 dp[k-2] // dp[k] = max{ dp[k-1], dp[k-2] + i } int temp = Math.max(curr, prev + i); prev = curr; curr = temp; // 循环结束时,curr 表示 dp[k],prev 表示 dp[k-1] }
return curr; }}