[dp]leetcode 198. House Robber
輸入:一個(gè)數(shù)組nums,每一個(gè)元素nums[i]表示第i個(gè)房間的價(jià)值。
輸出:一個(gè)搶劫犯能搶到又不會(huì)被警察發(fā)現(xiàn)的最大價(jià)值。
規(guī)則:如果搶劫犯搶了相鄰房間,那么報(bào)警裝置就會(huì)觸發(fā),警察會(huì)得到通知。
分析:我可以從第0個(gè)房間開(kāi)始,可能搶,也可能不搶,一直到最后一個(gè)房間,得到的價(jià)值取最大值就是結(jié)果。用回溯法吧。
分析2:這樣寫(xiě)完,畫(huà)決策分析樹(shù),或者打印idx,robbed,value,就會(huì)發(fā)現(xiàn)有些是重復(fù)的。2 false 重復(fù)了兩次。因?yàn)橐?jì)算的是最大價(jià)值,所以只需要保留一個(gè)最大值。所以我們可以使用緩存減少計(jì)算量。
0 false 0 1 true 1 2 false 1 3 true 4 3 false 1 1 false 0 2 true 2 3 false 2 2 false 0 3 true 3 3 false 0 private int[] nums;private int max = 0;private int[][] memo;public int rob(int[] nums) {this.nums = nums;max = 0;memo = new int[nums.length][2];rob(0,0,true);return max;}private void rob(int idx,int value,boolean robable){if(idx==nums.length){max = Math.max(max,value);}else{//System.out.println(idx+" "+robbed+" "+value);int idx2 = robable?1:0;if(value<memo[idx][idx2]){return;}memo[idx][idx2]=value;if(robable){rob(idx+1,value+nums[idx],false);}rob(idx+1,value,true);}}分析3:把以上代碼改為迭代版本。把變量名memo改為dp。
public int rob(int[] nums) {if(nums==null || nums.length==0) return 0;int n = nums.length;int[][] dp = new int[n][2];dp[0][0] = 0;dp[0][1] = nums[0];for(int i=1;i<n;i++){dp[i][0] = Math.max(dp[i-1][0],dp[i-1][1]);dp[i][1] = dp[i-1][0]+nums[i];}return Math.max(dp[n-1][0],dp[n-1][1]);}看著寫(xiě)出來(lái)的dp代碼我發(fā)現(xiàn)可以這樣整理自己的邏輯。
給定一個(gè)數(shù)組nums={1,2,3,1}。
如果只有第0個(gè)房間,可能搶也可能不搶。但這基本是廢話(huà),不搶顯然拿不到價(jià)值。
搶,得1,
不搶得0。
取最大值,得到的價(jià)值是1。
如果只有第0個(gè)和第1個(gè) 房間。對(duì)于房間1可能搶,也可能不搶。
如果搶第1個(gè)房間,那得到的價(jià)值是2,因?yàn)榈?個(gè)房間不搶的價(jià)值是0。
如果不搶第1個(gè)房間,那得到的價(jià)值是1,因?yàn)榈?個(gè)房間搶,得1,不搶得0,取最大值。Max(搶第1個(gè)房間,不搶第1個(gè)房間)=2。
如果只有第0個(gè)、第1個(gè) ,第2個(gè)房間。對(duì)于房間2可能搶,也可能不搶。
如果不搶第2個(gè)房間,那最后拿到的價(jià)值就是Max(搶第1個(gè)房間,不搶第1個(gè)房間)=2。
如果搶第2個(gè)房間,那最后拿到的價(jià)值就是不搶第1個(gè)房間的價(jià)值+nums[2]=1+3=4。
那最大的答案是Max(不搶第2個(gè)房間,搶第2個(gè)房間)=4。
分析到這里我們知道在新增一個(gè)房間的時(shí)候與上一個(gè)房間的搶和不搶獲得的價(jià)值有關(guān)系。最后答案是在當(dāng)前房間號(hào)搶和不搶狀態(tài)取最大值。這樣基本上dp方程就出來(lái)了。
嗯,這就是我的思考方式,是從回溯算法開(kāi)始,不斷優(yōu)化,最后整理到dp,然后總結(jié)出dp應(yīng)該這樣思考。當(dāng)然還缺少一步是內(nèi)存優(yōu)化。只與上一步的狀態(tài)有關(guān)系,可以用變量表示,而無(wú)需數(shù)組。
public int robV4(int[] nums) {if(nums==null || nums.length==0) return 0;int n = nums.length;int v0 = 0 ,v1=nums[0];for(int i=1;i<n;i++){int tmp0 = Math.max(v0,v1);int tmp1 = v0+nums[i];v0=tmp0;v1=tmp1;}return Math.max(v0,v1);}213 House Robber II
class Solution {public int rob(int[] nums) {if(nums==null || nums.length==0) return 0;if(nums.length==1) return nums[0];return Math.max(rob(nums,0,nums.length-2),rob(nums,1,nums.length-1));}public int rob(int[] nums,int start,int end) {int n = nums.length;int[][] dp = new int[2][n];dp[0][start] = nums[start];dp[1][start] = 0;for(int i=start+1;i<=end;i++){dp[0][i] = dp[1][i-1] + nums[i];dp[1][i] = Math.max(dp[0][i-1],dp[1][i-1]);}return Math.max(dp[0][end],dp[1][end]);} }總結(jié)
以上是生活随笔為你收集整理的[dp]leetcode 198. House Robber的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 五大常用算法总结
- 下一篇: Android代码优化——使用Andro