MicroSoft/LintCode:M-打劫房屋 II

题目


题目来源:Link


在上次打劫完一条街道之后,窃贼又发现了一个新的可以打劫的地方,但这次所有的房子围成了一个圈,这就意味着第一间房子和最后一间房子是挨着的。每个房子都存放着特定金额的钱。你面临的唯一约束条件是:相邻的房子装着相互联系的防盗系统,且 当相邻的两个房子同一天被打劫时,该系统会自动报警

给定一个非负整数列表,表示每个房子中存放的钱, 算一算,如果今晚去打劫,你最多可以得到多少钱 在不触动报警装置的情况下。

 注意事项

这题是House Robber的扩展,只不过是由直线变成了圈

样例

给出nums = [3,6,4], 返回 6, 你不能打劫34所在的房间,因为它们围成一个圈,是相邻的.


分析


(1)假设打劫 House 0,则 House 1 和 House n-1 都不能打劫,此时变成 House 2 ~ House n-2 间的无循环动态规划问题

(2)假设不打劫 House 0,则 House 1 和 House n-1 随便打不打劫,此时变成 House 1 ~ House n-1 间的无循环动态规划问题

(3)假设House s 与 House e 之间的动态规划问题

         假设对于 s, e 之间的某个House k

         假设 dp[k] 的含义:走过 House k 后,小偷能获得的最大钱数

         dp[k]有两个来源:

         1)打劫 House k,resa = dp[k-2]+nums[k]

         2)不打劫 House k,resb = dp[k-1]

         则 dp[k] = max(resa, resb)


代码


public class Solution {
    /**
     * @param nums: An array of non-negative integers.
     * return: The maximum amount of money you can rob tonight
     */
    public int houseRobber2(int[] nums) {
        // write your code here
        
        if(nums==null || nums.length==0) return 0;
        
        int n = nums.length;
        int[] dp = new int[n];
        
        if(n==1) return nums[0];
        
        //偷index=0的情况
        //则index=n-1不能偷;index=1不能偷
        //index=2~n-2,和一条街的情况一致
        int resa=0;
        if(n>3){
            resa=nums[0]+helper(nums,2,n-2);
        }
        
        //不偷index=0的情况
        //index=1~n-1,和一条街的情况一致
        int resb=0;
        if(n>1){
            resb=helper(nums,1,n-1);
        }
        
        return Math.max(resa,resb);
    }
    
    int helper(int[] nums, int s, int e){
        int len=e-s+1;
        
        if(len==1) return nums[s];
        
        int[] dp = new int[len];
        dp[0]=nums[s];
        dp[1]=Math.max(nums[s],nums[s+1]);
        
        int k=2;
        for(int i=s+k; i<=e; k++,i++){
            dp[k]=Math.max(dp[k-2]+nums[i],dp[k-1]);
        }
        return dp[len-1];
    }
}


你可能感兴趣的:(LintCode,动态规划,MicroSoft)