力扣213——打家劫舍 II

這一篇是上一篇的擴展,須要針對特殊狀況特殊考慮,固然其本質仍是動態規劃。
<!-- more -->git

原題

你是一個專業的小偷,計劃偷竊沿街的房屋,每間房內都藏有必定的現金。這個地方全部的房屋都圍成一圈,這意味着第一個房屋和最後一個房屋是緊挨着的。同時,相鄰的房屋裝有相互連通的防盜系統,若是兩間相鄰的房屋在同一夜被小偷闖入,系統會自動報警。github

給定一個表明每一個房屋存放金額的非負整數數組,計算你在不觸動警報裝置的狀況下,可以偷竊到的最高金額。segmentfault

示例 1:數組

輸入: [2,3,2]
輸出: 3
解釋: 你不能先偷竊 1 號房屋(金額 = 2),而後偷竊 3 號房屋(金額 = 2), 由於他們是相鄰的。

示例 2:url

輸入: [1,2,3,1]
輸出: 4
解釋: 你能夠先偷竊 1 號房屋(金額 = 1),而後偷竊 3 號房屋(金額 = 3)。
     偷竊到的最高金額 = 1 + 3 = 4 。

原題url:https://leetcode-cn.com/probl...spa

解題

這道題的變化是,一樣是一個數組,可是首尾相連了,也就是成了一個環,那麼本來遞推的方式也就行不通了,由於任何一個節點其實地位都相等了,也就找不到最初的狀態,沒法進行遞推了。code

但咱們能夠將如今的問題轉化成咱們已經解決的問題,仔細想一想。所謂的首尾相連,針對狀態進行劃分,能夠有三種狀況:leetcode

  1. 首尾節點都不選擇
  2. 只選擇首節點,不選擇尾結點
  3. 只選擇尾結點,不選擇首節點

由於咱們最終是要求出最大值,那麼只須要考慮後面兩種狀況,而這樣的話,又能夠轉化成了本來的線性數組了。get

接下來讓咱們看看代碼:博客

class Solution {
    public int rob(int[] nums) {
        if (nums.length == 0) {
            return 0;
        }

        if (nums.length == 1) {
            return nums[0];
        }

        // 由於收尾相連,沒法按照最初的動態規劃來作,由於沒有一個能夠開始的點。
        // 那麼就將未知問題轉化爲已知問題,針對首尾兩個節點,能夠有三種狀況:
        // 一、首尾節點都不選擇
        // 二、只選擇首節點,不選擇尾結點
        // 三、只選擇尾結點,不選擇首節點
        // 由於是要取最大值,且是非負整數數據,因此只考慮後兩種狀況

        return Math.max(
            // 只選擇首節點,不選擇尾結點
            calMax(nums, 0, nums.length - 2),
            // 只選擇尾結點,不選擇首節點
            calMax(nums, 1, nums.length - 1)
        );
    }

    public int calMax(int[] nums, int start, int end) {
        // 存儲當前位置,下一個位置,和再下一個位置的結果
        int current = 0;
        int next_1 = 0;
        int next_2 = 0;
        // 動態規劃,利用中間結果,尋找最大值
        for (int i = end; i >= start; i--) {
            current = Math.max(
                // 當前不偷
                next_1,
                // 當前偷
                nums[i] + next_2
            );
            next_2 = next_1;
            next_1 = current;
        }
        return current;
    }
}

提交OK。

總結

以上就是這道題目個人解答過程了,不知道你們是否理解了。這道題主要仍是利用動態規劃,只是須要你們進行思路轉化,將未知轉化爲 已知,從而解決問題。

有興趣的話能夠訪問個人博客或者關注個人公衆號、頭條號,說不定會有意外的驚喜。

https://death00.github.io/

公衆號:健程之道

相關文章
相關標籤/搜索