力扣第213题 打家劫舍|| c++ 附Java代码 将回环转线性 动态规划

题目

213. 打家劫舍 II

中等

相关标签

数组   动态规划

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

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

示例 1:

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

示例 2:

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

示例 3:

输入:nums = [1,2,3]
输出:3

思路和解题方法

  1. 首先rob函数接受一个整数数组nums,表示每个房屋中的金钱数量。首先判断数组的长度,如果为空,则返回0;如果只有一个房屋,则直接返回该房屋的金额。
  2. 然后,通过调用robmoney函数分别计算两种情况下的最大金额。robmoney函数接受一个整数数组nums、起始位置start和结束位置end,用于计算从第start个房屋到第end个房屋之间的最大金额。
  3. robmoney函数中,首先判断如果只有一个房屋,则直接返回该房屋的金额。然后创建一个大小与nums相同的dp数组,用于保存计算过程中的结果。将第一个房屋的金额存储在dp[start]中,将第二个房屋的金额选择偷或不偷的较大者存储在dp[start+1]中。
  4. 接下来,从第三个房屋开始遍历,计算每个房屋处的最大金额。对于每个房屋,可以选择偷或不偷。如果选择偷,则最大金额为前两个房屋的最大金额加上当前房屋的金额;如果选择不偷,则最大金额为前一个房屋的最大金额。取两者中较大的金额作为当前位置的最大金额,并将其存储在dp数组中。
  5. 最后,返回dp[end]作为最大金额的结果。

复杂度

        时间复杂度:

                O(n)

时间复杂度为O(n),其中n是房屋的数量。这是因为在该函数中,我们需要调用robmoney函数两次,每次计算的时间复杂度都是O(n),因此总时间复杂度为O(n)。

        空间复杂度

                O(n)

时间复杂度也为O(n),其中n是从startend之间的房屋数量。在该函数中,我们使用了一个dp数组来存储每个位置处的最大金额,因此空间复杂度为O(n)。

c++ 代码

class Solution {
public:
    int rob(vector& nums) {
        if(nums.size()==0) return 0;
        if(nums.size() ==1) return nums[0];
        int ans1 = robmoney(nums,0,nums.size() - 2); // 第一次计算从0到n-2的最大金额
        int ans2 = robmoney(nums,1,nums.size() - 1); // 第二次计算从1到n-1的最大金额
        return max(ans1,ans2); // 返回两次计算中的较大者
    }

    int robmoney(vector &nums,int start,int end)
    {
        if(end == start) return nums[start]; // 只有一个房屋时直接返回该房屋的金额
        vector dp(nums.size()); // 定义dp数组
        dp[start] = nums[start]; // 初始化dp数组
        dp[start+1] = max(nums[start],nums[start+1]);
        for(int i = start+2;i<=end;i++)
        {
            dp[i] = max(dp[i-2]+nums[i],dp[i-1]); // 计算当前位置的最大金额
        }
        return dp[end]; // 返回dp数组的最后一个元素作为结果
    }

};

Java代码

  1. rob函数接受一个整数数组nums,表示每个房屋中的金钱数量。首先进行一些预处理,如果nums为null或长度为0,则返回0。如果nums只有一个元素,则直接返回该元素的值。
  2. 然后,通过调用robAction函数分别计算两种情况下的最大金额。robAction函数接受一个整数数组nums、起始位置start和结束位置end,用于计算从第start个房屋到第end个房屋之间的最大金额。
  3. robAction函数中,我们使用三个变量x、y和z来记录计算过程中的最大金额。开始时,它们都初始化为0。然后,从第start个房屋开始遍历到第end-1个房屋。
  4. 在每一次遍历中,我们使用y暂存z的值,以便下一次计算。然后,我们通过比较y和x加上当前房屋的金额nums[i]的和,来更新z的值。最后,我们将y的值更新为z之前的值,以备下一次计算使用。
  5. 最终,返回z作为最大金额的结果。
  6. 这段代码的时间复杂度为O(n),其中n是房屋的数量。因为在robAction函数中,我们只进行了一次遍历,并对每个房屋进行常数时间的计算。所以整体的时间复杂度为O(n)。空间复杂度为O(1),因为我们只使用了三个额外的变量来保存计算过程中的值。

class Solution {
    public int rob(int[] nums) { // rob函数接收一个整数数组nums作为参数
        if (nums == null || nums.length == 0) // 如果数组为空,直接返回0
            return 0;
        int len = nums.length; // 获取数组长度
        if (len == 1) // 如果数组只包含一个元素,则直接返回该元素的值
            return nums[0];
        return Math.max(robAction(nums, 0, len - 1), robAction(nums, 1, len)); // 计算两种情况下的最大金额并返回较大者
    }

    int robAction(int[] nums, int start, int end) { // robAction函数用于计算从start到end之间的最大金额
        int x = 0, y = 0, z = 0; // 初始化三个变量x、y、z
        for (int i = start; i < end; i++) { // 遍历从start到end之间的房屋
            y = z; // 将上一个房屋的最大金额存储在y中
            z = Math.max(y, x + nums[i]); // 计算当前房屋的最大金额,并将结果存储在z中
            x = y; // 将上一个房屋的最大金额存储在x中
        }
        return z; // 返回最后一个房屋处的最大金额作为结果
    }
}

觉得有用的话可以点点赞,支持一下。

如果愿意的话关注一下。会对你有更多的帮助。

每天都会不定时更新哦  >人<  。

你可能感兴趣的:(leetcode,动态规划,数据结构,leetcode,java,c++,算法,动态规划)