算法-动态规划-打家劫舍2

小鱼儿 2023-02-12 08:28 79阅读 0赞

算法-动态规划-打家劫舍2

1 题目概述

1.1 题目出处

https://leetcode-cn.com/problems/house-robber-ii/

1.2 题目描述

你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都围成一圈,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。

给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,能够偷窃到的最高金额。

示例 1:

输入: [2,3,2]
输出: 3
解释: 你不能先偷窃 1 号房屋(金额 = 2),然后偷窃 3 号房屋(金额 = 2), 因为他们是相邻的。
示例 2:

输入: [1,2,3,1]
输出: 4
解释: 你可以先偷窃 1 号房屋(金额 = 1),然后偷窃 3 号房屋(金额 = 3)。
偷窃到的最高金额 = 1 + 3 = 4 。

2 动态规划

2.1 思路

思考,每一个房屋是否行窃如何决定?

  1. i个房屋最大价值 = Math.max(选当前+前i-2个房屋的价值和, 不选当前,前i-1个房屋的价值和)

那么这就是典型的动态规划问题。

但是这和打家劫舍1.0不同的是,这里首尾房屋成环,也不能同时选,所以需要分别考虑选择第一个或选择最后一个房屋的情况,取计算结果的大者为最终结果。

2.2 代码

  1. class Solution {
  2. public int rob(int[] nums) {
  3. int result = 0;
  4. // 选择某一个的条件是
  5. // 价值大于相邻的前一个
  6. if(nums == null || nums.length == 0){
  7. return result;
  8. }
  9. if(nums.length == 1){
  10. return nums[0];
  11. }
  12. // 分为两种情况考虑:选择第一个、不选第一个
  13. // 选择第一个,则不选第二个后最后一个
  14. int tmp1 = nums[0];
  15. if(nums.length == 4){
  16. tmp1 += nums[2];
  17. } else if(nums.length > 4){
  18. int dp[] = new int[nums.length];
  19. // 第i个房屋最大价值 = Math.max(选当前+前i-2个房屋的价值和,不选当前,前i-1个房屋的价值和)
  20. dp[2] = nums[2];
  21. dp[3] = Math.max(nums[2], nums[3]);
  22. for(int i = 4; i < nums.length - 1; i++){
  23. dp[i] = Math.max(nums[i] + dp[i-2], dp[i-1]);
  24. }
  25. tmp1 += dp[nums.length - 2];
  26. }
  27. // 不选第一个,则可选第二个后最后一个
  28. int tmp2 = 0;
  29. if(nums.length == 2){
  30. tmp2 = nums[1];
  31. }else{
  32. int dp[] = new int[nums.length];
  33. // 第i个房屋最大价值 = Math.max(选当前+前i-2个房屋的价值和,不选当前,前i-1个房屋的价值和)
  34. dp[1] = nums[1];
  35. dp[2] = Math.max(nums[1], nums[2]);
  36. for(int i = 3; i < nums.length; i++){
  37. dp[i] = Math.max(nums[i] + dp[i-2], dp[i-1]);
  38. }
  39. tmp2 += dp[nums.length - 1];
  40. }
  41. return Math.max(tmp1, tmp2);
  42. }
  43. }

冗余更少的代码:

  1. class Solution {
  2. public int rob(int[] nums) {
  3. int result = 0;
  4. // 选择某一个的条件是
  5. // 价值大于相邻的前一个
  6. if(nums == null || nums.length == 0){
  7. return result;
  8. }
  9. if(nums.length == 1){
  10. return nums[0];
  11. }
  12. // 分为两种情况考虑:选择第一个、不选第一个
  13. // 选择第一个,则不选第二个后最后一个
  14. int tmp1 = nums[0];
  15. tmp1 += rob(nums, 2, nums.length - 2);
  16. // 不选第一个,则可选第二个后最后一个
  17. int tmp2 = rob(nums, 1, nums.length - 1);
  18. return Math.max(tmp1, tmp2);
  19. }
  20. public int rob(int[] nums, int start, int end){
  21. if(start > nums.length || end < start){
  22. return 0;
  23. }else if (start == end){
  24. return nums[start];
  25. }
  26. int[] dp = new int[nums.length];
  27. dp[start] = nums[start];
  28. dp[start+1] = Math.max(nums[start], nums[start+1]);
  29. for(int i = start + 2; i <= end; i++){
  30. dp[i] = Math.max(dp[i - 1], dp[i - 2] + nums[i]);
  31. }
  32. return dp[end];
  33. }
  34. }

2.3 时间复杂度

在这里插入图片描述
O(N)

2.4 空间复杂度

O(N)

发表评论

表情:
评论列表 (有 0 条评论,79人围观)

还没有评论,来说两句吧...

相关阅读

    相关 序列型动态规划——打家劫舍2

    你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都 围成一圈 ,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防

    相关 序列类型动态规划——打家劫舍

    你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自

    相关 725-打家劫舍(动态规划)

    打家劫舍(动态规划) 你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在