leetCode 213. Robbery II: Dynamic programming of rooms connected in a ring. How to steal?

213. Robbery II - LeetCode

You are a professional thief planning to steal houses along the street, with a certain amount of cash hidden in each room. All the houses in this place  are arranged in a circle  , which means that the first house and the last house are right next to each other. At the same time, adjacent houses are equipped with interconnected anti-theft systems. If two adjacent houses are broken into by thieves on the same night, the system will automatically alarm  .

Given an array of non-negative integers representing the amount of money stored in each house, calculate the  maximum amount of money you can steal tonight without triggering the alarm device . 

Example 1:

Input: nums = [2,3,2]
 Output: 3
 Explanation: You cannot steal house No. 1 (amount = 2) and then steal house No. 3 (amount = 2), because they are adjacent.

Example 2:

Input: nums = [1,2,3,1]
 Output: 4
 Explanation: You can steal house No. 1 first (amount = 1), and then steal house No. 3 (amount = 3).
     Maximum amount stolen = 1 + 3 = 4.

Example 3:

Input: nums = [1,2,3]
 Output: 3

>>Ideas and analysis

It is similar to leetCode 198. Robbery dynamic programming , the only difference is that it forms a loop.

For an array, there are mainly the following situations when it forms a ring:

  • Case 1, consider not including the first and last elements

  • Case 2: Consider including the first element but not the last element.

  • Case 3: Consider including the tail element but not the first element.

If it is a linear array, it is leetCode 198. Robbery and dynamic programming . Once the loop is connected, I start to feel confused (=@__@=), not knowing where the starting point should be and where the end point should be. So should I choose between the starting point and the ending point? You will fall into this quagmire~

So where should we think about the rooms connected in a ring?

In a circular linear array, the first and last elements are adjacent. So if you can only select one of the first element and the last element, either the first element or the last element is selected, or neither the first or last element is selected. This can be reduced to 3 situations.

  • In the first case, the beginning and end are not considered. At this time, connecting into a loop has no impact on the linear array. Only consider the middle section, which is a linear array at this time, and can be solved using a linear array. LeetCode 198 is available. Robbery is handled in the same way.
  • In case two, the first element is considered, but the last element is not considered. So even if your first and last elements are adjacent to each other, it will not affect this. At this time, it is a linear array, and you can use a linear array to solve it. LeetCode 198 is available. Robbery is handled in the same way.
  • Case 3: The last element is considered, but the first element is not considered. So even if your first and last elements are adjacent to each other, it will not affect this. At this time, it is a linear array, and you can use a linear array to solve it. LeetCode 198 is available. Robbery is handled in the same way.

A careful analysis of Situation 2 and Situation 3 shows that Situation 1 is included. Case two considers both the first element and the middle part, and the optimal value obtained from the middle part is also included in case two. Some friends may be confused (O_O)? You have selected the first element in the second situation, how can it include my first situation? Thinking this way is actually a misunderstanding, because here is the scope of consideration, taking the first element into consideration, and it does not say that the first element must be selected. Whether to choose it or not is determined by our recursive formula. The range considered here is only the range of traversal, that is, the range of traversal recursion formula. In layman's terms, the range is only this large, so whether to select the first element or not is determined by a recursive formula. It does not say that the first element must be selected. Therefore, within this range, considering the optimal solution must include the optimal solution within the scope of situation one. The same applies to case three. The optimal solution within its range must also include the optimal solution within the range of case one.

The word "consider" is amazing! For example, in case three, although the tail element is considered to be included, it is not necessary to select the tail element! For case three, taking nums[1] and nums[3] is the largest! ! ! Scenario 2 and Scenario 3 both include Scenario 1 , so only Scenario 2 and Scenario 3 will be considered.

This is  the core code of leetCode 198. Robbery dynamic programming 

class Solution {
public:
    int rob(vector<int>& nums) {
        if (nums.size() == 0) return 0;
        if (nums.size() == 1) return nums[0];
        vector<int> dp(nums.size(),0);
        dp[0] = nums[0];
        dp[1] = max(nums[0],nums[1]);
        for(int i=2;i < nums.size();i++) {
            dp[i] = max(dp[i-1],dp[i-2] + nums[i]);
        }
        return dp[nums.size()-1];
    }
};
 
// 时间复杂度: O(n)
// 空间复杂度: O(n)

We extract it and use it as the robRange function. We can pass in the three parameters of nums, start, and end to realize the operation of intercepting the array , so as to realize the second and third cases, and then return the respective return values. Take a maximum value. In this way, this circular problem can be reduced to a linear array problem . Clear thinking~

// 注意注释中的情况二情况三,以及把198.打家劫舍的代码抽离出来了
class Solution {
public:
    int rob(vector<int>& nums) {
        if (nums.size() == 0) return 0;
        if (nums.size() == 1) return nums[0];
        int result1 = robRange(nums, 0, nums.size() - 2); // 情况二
        int result2 = robRange(nums, 1, nums.size() - 1); // 情况三
        return max(result1, result2);
    }
    // 198.打家劫舍的逻辑
    int robRange(vector<int>& nums, int start, int end) {
        if (end == start) return nums[start];
        vector<int> dp(nums.size());
        dp[start] = nums[start];
        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];
    }
};
  • Time complexity: O(n)
  • Space complexity: O(n)

#summary _

After the loop is formed, the concepts of "considering a room" and "stealing a room" are clarified, and then the scope of "consideration" for situations one, two, and three is clarified. Whether to steal a specific room or not is left to the recursive formula to choose .

When considering circular problems, sometimes circular problems are not conducive to our thinking. We will struggle with where the starting position is and where the ending position is. Should we choose the starting position or the end position? In fact, you can expand this ring appropriately into a linear structure, and then separately consider whether to select the first element and the last element, and then list three situations. Based on the analysis of these three situations, Situation 2 and Situation 3 include Situation 1, so the next step is a linear array problem, which is the same as leetCode 198. Robbery.

Reference and recommended articles and videos

Dynamic programming, if the rooms are connected into a ring, can we still steal? | LeetCode: 213. Robbery II_bilibili_bilibili

Code Random Record (programmercarl.com)

My past articles 

leetCode 198. Robbery Dynamic Planning_Heheda( ̄▽ ̄)"'s blog-CSDN blog

Guess you like

Origin blog.csdn.net/weixin_41987016/article/details/133409962