题目

image.png

思路

  • 思路一:暴力递归,由于不能连续偷窃,因此对于第i个房间有两种选择,偷与不偷,因此我们定义recur(int[] nums, int i)表示0到i中能偷窃的最大金额,其中递归分支是Math.max(recur(nums, i -2) + nums[i], recur(nums, i -1),将问题分解成小问题,当i<0时就是递归终止条件
  • 思路二:备忘录
  • 思路三:动态规划,递归的逆过程,定义dp[i]表示0到i中能够窃取的最大金额,转移方程:dp[i] = Math.max(dp[i-2] + nums[i], dp[i-1])。初始状态:dp[0] = nums[0],dp[1] = Math.max(nums[0],nums[1])
  • 思路四:优化dp数组的动态规划

代码

  1. //1.暴力递归,超时
  2. public int rob(int[] nums) {
  3. return recur(nums, nums.length - 1);
  4. }
  5. public int recur(int[] nums, int i) {
  6. if (i < 0) return 0;
  7. return Math.max(recur(nums, i - 2) + nums[i], recur(nums, i - 1));
  8. }
  9. //2.备忘录,超时
  10. int[] dp;
  11. public int rob(int[] nums) {
  12. dp = new int[nums.length];
  13. return recur(nums, nums.length - 1);
  14. }
  15. public int recur(int[] nums, int i) {
  16. if (i < 0) return 0;
  17. if (dp[i] != 0) return dp[i];
  18. dp[i] = Math.max(recur(nums, i - 2) + nums[i], recur(nums, i - 1));
  19. return dp[i];
  20. }
  21. //3.动态规划
  22. public int rob(int[] nums) {
  23. if (nums.length == 0) return 0;
  24. if (nums.length == 1) return nums[0];
  25. int[] dp = new int[nums.length];
  26. dp[0] = nums[0];
  27. dp[1] = Math.max(nums[0],nums[1]);
  28. for (int i = 2; i < nums.length; i++) {
  29. dp[i] = Math.max(dp[i - 2] + nums[i], dp[i - 1]);
  30. }
  31. return dp[nums.length - 1];
  32. }
  33. //4.优化dp数组的动态规划
  34. public int rob(int[] nums) {
  35. if (nums.length == 0) return 0;
  36. if (nums.length == 1) return nums[0];
  37. int p1 = nums[0], p2 = Math.max(nums[0],nums[1]), t = 0;
  38. for (int i = 2; i < nums.length; i++) {
  39. t = Math.max(p1 + nums[i], p2);
  40. p1 = p2;
  41. p2 = t;
  42. }
  43. return p2;
  44. }

打家劫舍