這一篇是上一篇的擴展,須要針對特殊狀況特殊考慮,固然其本質仍是動態規劃。
<!-- 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
由於咱們最終是要求出最大值,那麼只須要考慮後面兩種狀況,而這樣的話,又能夠轉化成了本來的線性數組了。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。
以上就是這道題目個人解答過程了,不知道你們是否理解了。這道題主要仍是利用動態規劃,只是須要你們進行思路轉化,將未知轉化爲 已知,從而解決問題。
有興趣的話能夠訪問個人博客或者關注個人公衆號、頭條號,說不定會有意外的驚喜。
公衆號:健程之道