当前位置: 首页 > article >正文

代码随想录算法训练营第三十九天|Day39 动态规划

198.打家劫舍

视频讲解:https://www.bilibili.com/video/BV1Te411N7SX

https://programmercarl.com/0198.%E6%89%93%E5%AE%B6%E5%8A%AB%E8%88%8D.html

思路

#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[numsSize];
    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];
}

​

学习反思

使用动态规划的思想来解决打家劫舍问题。首先定义了一个max宏来返回两个数中较大的一个。然后定义了一个dp数组,dp[i]表示在前i个房屋中能够偷到的最大金额。初始情况下,当只有一个房屋时,最大金额就是该房屋的金额。当有两个房屋时,最大金额为两个房屋金额的较大值。然后通过一个循环来计算每个房屋能够偷到的最大金额。对于第i个房屋,有两种选择:偷或者不偷。如果偷第i个房屋,则最大金额为dp[i-2]加上第i个房屋的金额;如果不偷第i个房屋,则最大金额为dp[i-1]。取这两个值中的较大值作为dp[i]的值。最后返回dp[numsSize-1],即在前numsSize个房屋中能够偷到的最大金额。该方法的时间复杂度为O(n)。

213.打家劫舍II

视频讲解:https://www.bilibili.com/video/BV1oM411B7xq

https://programmercarl.com/0213.%E6%89%93%E5%AE%B6%E5%8A%AB%E8%88%8DII.html

思路

#define max(a, b) ((a) > (b) ? (a) : (b))
int robRange(int* nums, int start, int end, int numsSize) {
    if (end == start) return nums[start];
    int dp[numsSize];
    dp[start] = nums[start];
    dp[start + 1] = max(nums[start], nums[start + 1]);
    for (int i = start + 2; i <= end; i++) {
        dp[i] = max(dp[i - 2] + nums[i], dp[i - 1]);
    }
    return dp[end];
}
int rob(int* nums, int numsSize) {
    if (numsSize == 0) return 0;
    if (numsSize == 1) return nums[0];
    int result1 = robRange(nums, 0, numsSize - 2, numsSize); 
    int result2 = robRange(nums, 1, numsSize - 1, numsSize); 
    return max(result1, result2);
}

学习反思

首先定义了一个私有函数robRange,它的功能是求解在某个范围内房屋能够偷到的最大金额。robRange的参数包括nums数组、起始位置start、结束位置end以及数组长度numsSize。它的返回值是在[start, end]范围内能够偷到的最大金额。robRange的实现基本和原来的动态规划解法相同,只是将数组dp的大小改为了numsSize,并且只计算了在[start, end]范围内的结果。然后,在主函数rob中,首先处理特殊情况,当numsSize为0或1时,直接返回结果。然后调用robRange函数分别计算从第0个房屋到倒数第二个房屋和从第1个房屋到最后一个房屋能够偷到的最大金额。最后取这两个结果中的较大值作为最终的结果。这种分段处理的方式能够解决循环数组的问题,时间复杂度仍然是O(n)

337.打家劫舍III

视频讲解:https://www.bilibili.com/video/BV1H24y1Q7sY

https://programmercarl.com/0337.%E6%89%93%E5%AE%B6%E5%8A%AB%E8%88%8DIII.html

思路

int *robTree(struct TreeNode *node) {
    int* amounts = (int*) malloc(sizeof(int) * 2);
    memset(amounts, 0, sizeof(int) * 2);
    if(node == NULL){
        return amounts;
    }
    int * left = robTree(node->left);
    int * right = robTree(node->right);
    amounts[1] = node->val + left[0] + right[0];
    amounts[0] = max(left[0], left[1]) + max(right[0], right[1]);
    return amounts;
}
int rob(struct TreeNode* root) {
    int * dp = robTree(root);
    return max(dp[0], dp[1]);
}

学习反思

函数robTree是递归函数,它接受一个树节点作为参数,返回一个包含两个元素的数组amounts,其中amounts[0]表示不打劫当前节点能获得的最大金额,amounts[1]表示打劫当前节点能获得的最大金额。首先,函数动态为amounts分配了一个包含两个元素的数组,并使用memset函数将数组初始化为0。接下来,如果当前节点node为空,则直接返回amounts。否则,函数递归地调用robTree函数,分别对左子树和右子树进行打劫操作,并将返回的结果保存在leftright指针中。然后,计算打劫当前节点的最大金额。根据题目要求,打劫当前节点时,不能打劫其直接相连的子节点。因此,打劫当前节点的最大金额等于当前节点的值加上左子树不打劫根节点的最大金额加上右子树不打劫根节点的最大金额。将这个值保存在amounts[1]中。接着,计算不打劫当前节点的最大金额。根据题目要求,不打劫当前节点时,可以选择打劫其直接相连的子节点。因此,不打劫当前节点的最大金额等于左子树的两种选择中的最大金额加上右子树的两种选择中的最大金额。将这个值保存在amounts[0]中。最后,返回amounts数组。函数rob是主函数,它调用robTree函数来计算二叉树中打劫的最大金额。首先,调用robTree函数得到一个包含两个元素的数组dp。然后,返回dp[0]dp[1]中的较大值作为结果。

总结

今天是打家劫舍的一天,这个系列不算难,加油!!!


http://www.kler.cn/a/384331.html

相关文章:

  • Python OpenCV 傅里叶变换
  • MinGW-w64_10.0.0 + GCC12_x86_64-12.2.0-release-posix-seh-msvcrt-rt_v10-rev2.zip
  • 这款神器,运维绝杀 !!!
  • 使用sealos部署的集群在部署metrics-server时日志x509
  • 基于梧桐数据库的实时数据分析解决方案
  • 高效作业之Mybatis缓存
  • 汽车广告常见特效处理有哪些?
  • 备战软考Day05-数据库系统基础知识
  • centos查看硬盘资源使用情况命令大全
  • 深入解析Linux内核中断管理:从IRQ描述符到irq domain的设计与实现
  • 宏集Cogent DataHub: 高效实现风电场数据集中管理与自动化
  • 股指期货交易中,如何应对震荡行情?
  • mmpose框架进行人体姿态识别模型HRNet训练
  • AJAX 全面教程:从基础到高级
  • [react]10、react性能优化
  • 前端三件套-css
  • 二分答案—愤怒的牛-P1676 [USACO05FEB] Aggressive cows G
  • 11/6密码学 Des对称加密设计
  • 软考系统架构设计师论文:云上自动化运维及其应用
  • mysql查表相关练习
  • 6.0、静态路由
  • 夜天之书 #103 开源嘉年华纪实
  • Chromium127编译指南 Mac篇(六)- 编译优化技巧
  • 苍穹外卖 管理端订单分页查询
  • 【Android】Service
  • 在数据抓取的时候,短效IP比长效IP有哪些优势?