C语言----打家劫舍(leetcode三题汇总)

目录

一:打家劫舍

二:打家劫舍II

三:打家劫舍III


一:打家劫舍

 解题思路:

该题用动态规划求解,简单易懂

1,抢劫的房屋数少于两个情况(包含两个),如果就一个房屋,则肯定就抢他了,别无他家;如果房屋有两家,则抢劫富有的那家

2,抢劫的房屋数大于两个,这会就该想想转移方程怎么写了,小偷光顾到了第i家,这时候小偷有两个选择,偷或者不偷,假如小偷不偷第i家,则此时小偷已经偷到的钱为dp[i-1],假如小偷要偷第i家,则小偷偷到的是dp[i-2]+nums[i]。从i-2家偷过来肯定是可以并且安全的。

3,比较偷还是不偷的大小,取大的

#define MAX(x,y) (x)>(y)?(x):(y)
int rob(int* nums, int numsSize)
{
    if(numsSize == 0)   return 0;
    if(numsSize == 1)   return nums[0];
    if(numsSize == 2)   return MAX(nums[0],nums[1]);
    int *dp = (int *)malloc(sizeof(int)*numsSize);
    memset(dp,0,numsSize);

    int i = 0;
    int res = 0;
    for(i=0; i<numsSize; i++)
    {
        if(i == 0)
        {
            dp[i] = nums[0];
            continue;
        }  
        if(i == 1)
        {
            dp[i] = MAX(nums[0],nums[1]);
            continue;
        }
        dp[i] = MAX(dp[i-1],dp[i-2]+nums[i]);
        res = MAX(res,dp[i]);  
    }
    return res;
}

运行结果:

 二:打家劫舍II

 解题思路:

可以把上一题看做这一题的子集,头尾的房屋其是一家的,不能同时偷,那我们可以分两种情况

1,小偷从第1家开始光顾,在倒数第二家停下来

2,小偷从第2家开始光顾,在最后一家停下来

这样就完美的避免了,同时抢劫了第一家和最后一家

#define MAX(x,y) (x)>(y)?(x):(y)

int subRob(int *nums, int numsSize)
{
    if(numsSize == 0)   return 0;
    if(numsSize == 1)   return nums[0];
    if(numsSize == 2)   return MAX(nums[0],nums[1]);

    
    int *dp = (int *)malloc(sizeof(int)*numsSize);
    memset(dp,0,numsSize);

    int i = 0;
    int res = 0;
    for(i=0; i<numsSize; i++)
    {
        if(i == 0)
        {
            dp[i] = nums[0];
            continue;
        }  
        if(i == 1)
        {
            dp[i] = MAX(nums[0],nums[1]);
            continue;
        }
        dp[i] = MAX(dp[i-1],dp[i-2]+nums[i]);
        res = MAX(res,dp[i]);  
    }
    return res;
}

int rob(int* nums, int numsSize)
{
    if(numsSize == 0)   return 0;
    if(numsSize == 1)   return nums[0];
    if(numsSize == 2)   return MAX(nums[0],nums[1]);

    return MAX(subRob(nums,numsSize-1),subRob(nums+1,numsSize-1));
}

运行结果:

 三:打家劫舍III

 该题我是看了答案理解的,也说说答案的思路吧

1,对于一个二叉树的节点,我们有两个选择,打劫或者不打劫

2,比如实例2中的节点3,打劫该节点的话,则4,5节点均不能打劫,因为与3相连,则这时候能打劫到的最大数即节点3的值加上节点4和5分支的最大值

3,不打劫节点3,则选择就比较多了,节点4和5都可以打劫也可以不打劫,只需要选出其中你的最大值即可

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */


struct SubtreeStatus {
    int selected;
    int notSelected;
};

struct SubtreeStatus dfs(struct TreeNode *node) {
    if (!node) {
        return (struct SubtreeStatus){0, 0};
    }
    struct SubtreeStatus l = dfs(node->left);
    struct SubtreeStatus r = dfs(node->right);
    int selected = node->val + l.notSelected + r.notSelected;
    int notSelected = fmax(l.selected, l.notSelected) + fmax(r.selected, r.notSelected);
    return (struct SubtreeStatus){selected, notSelected};
}

int rob(struct TreeNode *root) {
    struct SubtreeStatus rootStatus = dfs(root);
    return fmax(rootStatus.selected, rootStatus.notSelected);
}

运行结果:

  • 5
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ftzchina

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值