leetcode213. 打家劫舍 II

你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都围成一圈,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。

给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,能够偷窃到的最高金额。

示例 1:

输入: [2,3,2]
输出: 3
解释: 你不能先偷窃 1 号房屋(金额 = 2),然后偷窃 3 号房屋(金额 = 2), 因为他们是相邻的。


示例 2:

输入: [1,2,3,1]
输出: 4
解释: 你可以先偷窃 1 号房屋(金额 = 1),然后偷窃 3 号房屋(金额 = 3)。
     偷窃到的最高金额 = 1 + 3 = 4 。


链接:https://leetcode-cn.com/problems/house-robber-ii

【思路】

很容易想到一种思路,只需要判断是否打劫当前房屋,若打劫,则相邻房屋自动排出不打劫;若当前房屋不打劫,那么相邻房屋是否打劫还未定。dp,我们考虑前n户房屋。可以想到dp方程:dp[i]=max(dp[i-1],dp[i-2]+nums[i]);但是这里需要注意的房屋排列是一个环,也就是第一户房屋和最后一户房屋也是相邻的,因此这里分两种情况考虑,1.若第一户人家被打劫,那么最后一户人家一定不能被打劫,也就是考虑除去最后一户人家的情况。2.若第一户人家不被打劫,那么考虑除去第一户人家的范围

int max(int a,int b){
    return a>b?a:b;
}
int cal(int *nums,int start,int end){
    int i,dp[end-start+2];
    memset(dp,0,sizeof(dp));
    for(i=start;i<=end;i++){
        dp[i]=nums[i];
    }
    dp[start+1]=max(nums[start],nums[start+1]);
    for(i=start+2;i<=end;i++){
        dp[i]=max(dp[i-1],dp[i-2]+nums[i]);
    }
    return dp[end];
}
int rob(int* nums, int numsSize){
    int i,j,tmp;
    int dp[numsSize+1];
    if(numsSize==0)
        return 0;
    if(numsSize==1)
        return nums[0];
    if(numsSize==2)
        return max(nums[0],nums[1]);
//cal(nums,0,numsSize-2)第一户被打劫,cal(nums,1,numsSize-1)第一户不被打劫
    return max(cal(nums,0,numsSize-2),cal(nums,1,numsSize-1));
}

此题也可以直接采用二维数组表示从i到j户人家的情况,这里使用i主要是为了判断第一户人家是否被打劫;若i==第一户&&j==最后一户,那么方程为dp[i][j]=max(dp[i][j-1],dp[i+1][j-2]+nums[j]);表示选择最后一户打劫时第一户不打劫。

int max(int a,int b){
    return a>b?a:b;
}
int rob(int* nums, int numsSize){
    int i,j;
    int dp[numsSize+1][numsSize+1];
    if(numsSize==0)
    return 0;
    if(numsSize==1)
    return nums[0];
    if(numsSize==2)
    return max(nums[0],nums[1]);
    memset(dp,0,sizeof(dp));
    for(i=0;i<numsSize;i++){
        dp[i][i]=nums[i];
    }
    for(i=0;i<numsSize-1;i++){//后面j-2会用到,提前计算
        dp[i][i+1]=max(nums[i],nums[i+1]);
    }
    dp[0][1]=max(nums[0],nums[1]);
    for(j=2;j<numsSize;j++){
        for(i=j-1;i>=0;i--){
            if(i==0&&j==numsSize-1)
                dp[i][j]=max(dp[i][j-1],dp[i+1][j-2]+nums[j]);
            else
                dp[i][j]=max(dp[i][j-1],dp[i][j-2]+nums[j]);
        }
    }
    return dp[0][numsSize-1];
}
扫描二维码关注公众号,回复: 9005302 查看本文章
发布了129 篇原创文章 · 获赞 105 · 访问量 23万+

猜你喜欢

转载自blog.csdn.net/sunshine_lyn/article/details/104190291