代码随想录训练营32day-动态规划5

一、198 打家劫舍

你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警

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

思路:

当前房屋有2个状态:偷和不偷

若是当前房屋被偷,那么前一个房屋必不能被偷(触发警报),前2个房屋可以被偷,

若是当前房屋没被偷,那么前一个房屋可以被偷。

动态规划步骤:

1 dp[i]代表第i个房屋,前面i个房屋被偷的最大金额;

2 状态转移公式:

   若偷第i家,那么dp[i] = nums[i] + dp[i-2]

   若是不偷第i家,那么dp[i] = dp[i-1];

找最大的:dp[i] = MAX(nums[i] + dp[i-2], dp[i-1])

3 初始化:i = 0时,dp[0] = nums[0], dp[1]=MAX(dp[0], dp[1]);

4 遍历顺序i=2开始,一次遍历nums

#define MAX(a, b)  (a) > (b)? (a) : (b)
int rob(int* nums, int numsSize) {
    if(numsSize == 0)
      return 0;
    if(numsSize == 1)
      return nums[0];
    int* dp = (int*)calloc(numsSize + 1, sizeof(int));
    dp[0] = nums[0];
    dp[1] = MAX(nums[0], nums[1]);
    for(int i = 2; i < numsSize; i++)
    {
        dp[i] = MAX(dp[i-1], dp[i-2] + nums[i]);
    }

    return dp[numsSize -1];
}

二、213 打家劫舍II

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

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

思路:

与第一题相对比,题目限制就是成环了。限制点就在于首尾两点的选择上。

状态1:不考虑首元素;

状态2:不考虑尾元素;

状态3:不考虑首尾元素;

在第一题基础上改动:

#define MAX(a, b)  (a) > (b)? (a) : (b)
/**注意区间开闭**/
int robFunc(int* nums, int start, int end)
{
    if(end - 1 == start)
      return nums[start];
    int* dp = (int*)calloc(end - start + 1, sizeof(int));
    dp[start] = nums[start];
    dp[1 + start] = MAX(nums[start], nums[start + 1]);
    for(int i = start + 2; i < end; i++)
    {
        dp[i] = MAX(dp[i-1], dp[i-2] + nums[i]);
    }
    
    return dp[end - 1];
}

int rob(int* nums, int numsSize) {
    if(numsSize == 0)
      return 0;
    if(numsSize == 1)
      return nums[0];
    int ret_first = robFunc(nums, 0, numsSize - 1);
    int ret_second = robFunc(nums, 1, numsSize);
    return MAX(ret_first, ret_second);
}

三、337 打家劫舍III

小偷又发现了一个新的可行窃的地区。这个地区只有一个入口,我们称之为 root 。

除了 root 之外,每栋房子有且只有一个“父“房子与之相连。一番侦察之后,聪明的小偷意识到“这个地方的所有房屋的排列类似于一棵二叉树”。 如果 两个直接相连的房子在同一天晚上被打劫 ,房屋将自动报警。

给定二叉树的 root 。返回 在不触动警报的情况下 ,小偷能够盗取的最高金额 。

思路:

这里数据结构是二叉树,根据动态规划的步骤:

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */
// int rob(struct TreeNode* root) {
    
// }
#define MAX(a, b)  (a) > (b)? (a) : (b)

int* robTree(struct TreeNode* cur)
 {
     if(cur == NULL)
     {
        int*dp = (int*)malloc(sizeof(int)*2);
         dp[0] = 0;
         dp[1] = 0;
         return dp;
     }
     int*left_dp = robTree(cur -> left);
     int*right_dp = robTree(cur -> right);

     int* dp = (int*)malloc(sizeof(int)*2);
     dp[1] = left_dp[0] + right_dp[0]+ cur->val;
     dp[0] = fmax(left_dp[0],left_dp[1]) + fmax(right_dp[0],right_dp[1]);
     return dp;
 }

int rob(struct TreeNode* root){
    int* ret = (int*)malloc(sizeof(int)*2);
    ret = robTree(root);
    return fmax(ret[0],ret[1]);
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值