Kyyyyyy 动态规划入门 简单到噗噗捏捏题

Problem_link: 213. 打家劫舍 II

前言

偷东西是不对的


思路

思路和打家劫舍普通差不多,只是多了一个头尾不能同时偷的条件,既然这样,就遍历两次,第一次不管第一家,第二次不管最后一家。


解题方法

  • 边界
    l e n ( n u m s ) < = 3 len(nums)<=3 len(nums)<=3时,只能选一家,所以挑最大的选就行了。代码是可以处理2家以上的情况的,这样直接返回略快一些。

  • 定义状态
    每家我们都有偷和不偷两种情况:
  1. 如果偷,它的前一家就不能偷,结果就等于前一家不偷的情况加上这家的金额。
  2. 如果不偷,结果就是前一家偷和前一家不偷两种情况中的最大值。
    所以, d p [ i ] [ 0   o r   1 ] dp[i][0\ or\ 1] dp[i][0 or 1]表示第i+1家(i从0开始)偷(1)和不偷(0)两种情况的最优解。
    { d p [ 0 ] [ 0 ] = 0 第一家不偷 d p [ 0 ] [ 1 ] = n u m s [ 0 ] 第一家偷 d p [ i ] [ 0 ] = m a x ( d p [ i − 1 ] [ 1 ] , d p [ i − 1 ] [ 0 ] ) 不偷这一家 d p [ i ] [ 1 ] = d p [ i − 1 ] [ 0 ] + n u m s [ i ] 偷这一家 \begin{cases} dp[0][0] = 0 & 第一家不偷 \\ dp[0][1] = nums[0]& 第一家偷 \\ dp[i][0] = max(dp[i-1][1],dp[i-1][0])& 不偷这一家 \\ dp[i][1] = dp[i-1][0]+nums[i] & 偷这一家 \end{cases} dp[0][0]=0dp[0][1]=nums[0]dp[i][0]=max(dp[i1][1],dp[i1][0])dp[i][1]=dp[i1][0]+nums[i]第一家不偷第一家偷不偷这一家偷这一家

  • 首尾问题
    遍历两次,让首尾不同时出现就可以解决。
  • 最终结果
    把两次遍历的结果都做最大值比较,结果就出来了。

复杂度

  • 时间复杂度:
    O ( n ) O(n) O(n)

  • 空间复杂度:
    O ( n ) O(n) O(n)

Code

int max(int a,int b){
    return a>b?a:b;
}
// 偷家范围
int robRange(int* nums, int start, int end) {
    // 对第i个房子偷和不偷,0是不偷,1是偷
    int dp[100][2] = {{0}};
    dp[start][0] = 0;
    dp[start][1] = nums[start];
    for (int i = start+1; i < end; i++) {
        dp[i][0] = max(dp[i-1][0],dp[i-1][1]);
        dp[i][1] = dp[i-1][0]+nums[i];
    }
    return max(dp[end-1][0],dp[end-1][1]);
}
int rob(int* nums, int numsSize){
    // 边界
    
    if(numsSize<=3){
        int res = nums[0];
        for(int i=1;i<numsSize;i++){
            res = max(res,nums[i]);
        }
        return res;
    }

    // 不管第一家的结果和不管最后一家的结果进行比较
    return max(robRange(nums,1,numsSize),robRange(nums,0,numsSize-1));
}

可以发现每次只使用上一次偷家状态,所以可以将空间优化为常量。


class Solution:
    def rob(self, nums: List[int]) -> int:
        # 边界
        if(len(nums)<=3):
            return max(nums)

        def robRange(nums: List[int],start,end) ->int:
            # 偷上一家
            stealFami   = nums[start]
            # 不偷上一家
            notstealFami= 0

            # 偷这一家
            notstealThisFami=None
            # 不偷这一家
            stealThisFami   =None
            for i in range(start+1,end):
                notstealThisFami = max(stealFami,notstealFami)
                stealThisFami   = notstealFami+nums[i]
                stealFami,notstealFami = stealThisFami,notstealThisFami
            return max(stealFami,notstealFami)

        return max(robRange(nums,1,len(nums)),robRange(nums,0,len(nums)-1))

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值