动态规划类题1

首先是前些天做过打家劫舍的题。有一点印象,然后也看了时间复杂度最小的,然后自己又重新写了下。

int rob(int* nums, int numsSize) {
    if(numsSize==0)
    return 0;
    else if(numsSize==1)
    return nums[0];
    else
    {
        int *dp=(int *)malloc(numsSize *sizeof(int));
dp[0]=nums[0];
dp[1]=fmax(dp[0],nums[1]);
for(int i=2;i<numsSize;i++)
{
dp[i]=fmax(dp[i-2]+nums[i],dp[i-1]);
}
return dp[numsSize-1];
    }
}

感觉最关键的还是这几步

dp[0]=nums[0];
dp[1]=fmax(dp[0],nums[1]);

dp[i]=fmax(dp[i-2]+nums[i],dp[i-1]);

找到dp[]具体表示的什么含义就好。

然后今天看到这一题

 刚开始想的是不是先把所有的数先排下序在一个一个数排除确定,写了大概几个小时还是有各种错误,最后再修改下结果运行超时,当时确实不知道怎么写了,然后就往前翻看到了打家劫舍这题,觉得相邻的不偷与这两个跟num[i]+1和num[i]-1,有点像,但具体怎么写还是没有想出来。最后看了评论区一个同学用python写的,有明白一点,然后自己开始用C写,还是各种错误,又改改了,最终通过。代码,注释如下

int deleteAndEarn(int* nums, int numsSize) {
    // 如果数组为空,直接返回 0
    if (numsSize == 0) return 0;

    // 如果数组只有一个元素,直接返回该元素的值
    if (numsSize == 1) return nums[0];

    // 找出数组中的最大值
    int maxnumber = 0;
    for (int i = 0; i < numsSize; i++) {
        if (maxnumber < nums[i]) {
            maxnumber = nums[i];
        }
    }

    // 为 `sum` 数组分配内存,并用 `calloc` 初始化为 0
    // `sum[i]` 表示所有值为 `i` 的元素的总和
    int *sum = (int*)calloc(maxnumber + 1, sizeof(int));
    for (int i = 0; i < numsSize; i++) {
        sum[nums[i]] += nums[i];
    }

    // 为 `dp` 数组分配内存
    // `dp[i]` 表示考虑到最大值为 `i` 时的最大得分
    int *dp = (int*)malloc((maxnumber + 1) * sizeof(int));

    // 初始化 `dp` 数组的前两个元素
    dp[0] = sum[0];
    if (maxnumber > 0) {
        dp[1] = (sum[1] > sum[0]) ? sum[1] : sum[0];
    }

    // 填充 `dp` 数组,使用动态规划的方式
    for (int i = 2; i <= maxnumber; i++) {
        // 对于每个 `i`,我们可以选择不删除 `i`(即保留 `dp[i-1]`),
        // 或选择删除 `i`(即加上 `dp[i-2] + sum[i]`)
        dp[i] = (dp[i-2] + sum[i] > dp[i-1]) ? (dp[i-2] + sum[i]) : dp[i-1];
    }

    // 返回最大得分,即处理到最大值 `maxnumber` 时的得分
    return dp[maxnumber];
}

总结大体思路就是用nums[i]作为另一个数组sum[]的下标,那么该题就可以转化为打家劫舍相邻的两个数不取,并且取最大值了,感觉这题真的很巧妙。虽然时间复杂度不是最低的,但真的尽力了,而且这题maxnumber>0也是摸索着探索的条件,另外不知道这题为啥用不了max和fmax函数,只能按照上面那样写,而且第一题打家劫舍也不知道为什么只能用fmax 函数,用不了max函数,求懂得大佬解答一下,谢谢!!! 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值