代碼隨想錄算法訓練營|第五十天|198.打家劫舍、213.打家劫舍II、337.打家劫舍III。刷题心得(c++)

目录

讀題

198.打家劫舍

自己看到题目的第一想法

看完代码随想录之后的想法

213.打家劫舍II

自己看到题目的第一想法

看完代码随想录之后的想法

337.打家劫舍III

自己看到题目的第一想法

看完代码随想录之后的想法

198.打家劫舍 - 實作

思路

Code

213.打家劫舍II - 實作

思路

Code

337.打家劫舍III - 實作

思路

Code

總結

自己实现过程中遇到哪些困难

今日收获,记录一下自己的学习时长

相關資料

第九章 动态规划part09


讀題

198.打家劫舍

自己看到题目的第一想法

這感覺是跟01 背包問題中的最大價值很像,但是因為相鄰的部分不能被rob,所以在做背包的遞迴時,需要將i += 2?

沒有搞得很清楚這個問題的含意,先看題解

看完代码随想录之后的想法

當前的屋子偷與不偷取決於前一個房子以及前兩個房子是否被偷了,需要先有這想法

之後去定義dp數組時,定義i 以內的房屋最高偷多少錢為dp[i]

遞推公式也要根據前面的思維

去看dp[i - 2] + 當前value比較高還是dp[i - 1]比較高,來取值

在根據遞推公式初始化dp[0] 跟 dp[1] 因為不能操控到空指針

213.打家劫舍II

自己看到题目的第一想法

看完我在想說初始化時,要改為三個因為避免前後都取,前三個只能取最大,因為環形的緣故,但是要去思考怎麼讓後面的數值也不要跟前面的相同,就有些犯難了,我不清楚怎麼樣才能夠避開這個環形

看完代码随想录之后的想法

很清晰,主要分三種狀況,首尾都不取、取首元素、取尾元素,分為這三種狀況

其實主要是把取首元素,取尾元素這兩種狀況分別出來,比較哪個比較大

至於狀況一,則是在狀況二、三時,就解決了。

337.打家劫舍III

自己看到题目的第一想法

這題讓我想到之前有一題是裝設監視器,也是分情況,二叉樹的動態規劃要怎麼做,很沒有想法,但大致上知道是說,是後序遍歷,選擇左右子樹比較有錢的部分,但感覺也不太對,先來看題解。

看完代码随想录之后的想法

雖然都是後續遍歷,但是是紀錄有沒有偷過

因為要用到二叉樹的遍歷,所以要使用遞迴

首先要確認傳入參數和返回值,返回的數組就是dp數組,傳入值則是樹節點

定義dp數組的含意,下標為0定為不偷該節點的最大金額,下標為1定為偷該節點的最大金額

dp數組的長度為2,因為遞迴的過程中,系統會保存每一層的參數

確認終止條件,假設遇到空節點,那都是0

確定遍歷順序,後續遍歷,透過遞回函樹的返回值來進行計算

透過遞歸左節點,得到左節點偷與不偷的金額

透過遞歸右節點,得到右節點偷與不偷的金額

確定單層遞歸的邏輯

偷當前節點左右孩子就不能偷,因為相鄰 va1 = cur→val + left[0] + right[0]

不偷當前節點,左右節點都可以偷,就是偷最大的 val2 = max(left[0] + left[1]) + max(right[0], right[1]);

遞推公式就會變成 max(val1 ,val2)

198.打家劫舍 - 實作

思路

  1. 定義DP數組以及下標的含意

    dp[i]: 在房屋i (包含i)之前,所能得到的最高金額是dp[i]。

  2. 遞推公式

    要偷這個房屋,還是不偷這個房屋,取決與前一個以及前兩個

    前一個房屋要偷,當下就不能偷,因為題意的緣故 dp[i - 1]

    當下的要偷,跳過前一個的房屋也要偷,因為題意是不能相鄰而已,dp[i - 2] + nums[i];

    所以dp 公式為: dp[i] = max ( dp[i - 1], dp[i -2] + nums[i]);

  3. 根據遞推公式,確定DP數組如何初始化

    dp[0] = nums[0]

    dp[1] = max(nums[0], nums[1])

    可以想成這是從哪個開始偷,起始金額比較高

  4. 確定遍歷順序

    因為是由前兩個數值所推出來的,所以是由前往後遍歷。

Code

class Solution {
public:
    int rob(vector<int>& nums) {
        if(nums.size() == 1) return nums[0];
        vector<int> dp (nums.size(), 0);
        dp[0] = nums[0];
        dp[1] = max(nums[0], nums[1]);
        for(int i = 2; i < nums.size(); i++) {
            dp[i] = max(dp[i - 1], dp[i - 2] + nums[i]);
        }
        return dp[nums.size() - 1];
    }
};

 

213.打家劫舍II - 實作

思路

  1. 定義DP數組以及下標的含意

    dp[i]: 在房屋i (包含i)之前,所能得到的最高金額是dp[i]。

  2. 遞推公式

    遞推公式跟打家劫舍依樣

    所以dp 公式為: dp[i] = max ( dp[i - 1], dp[i -2] + nums[i]);

  3. 根據遞推公式,確定DP數組如何初始化

    dp[start] = nums[start]

    dp[start] = max(nums[start], nums[start + 1])

    可以想成這是從哪個開始偷,起始金額比較高

  4. 確定遍歷順序

    主要有三種情況,這裡著重處理後兩種

    第一種,首尾都不取

    第二種,只取首數

    第三種,只取尾數

    遞推的部分都是由前往後,但主要是加上兩種狀況的分別遞推

Code

class Solution {
public:
    int rob(vector<int>& nums) {
            if(nums.size() == 1) return nums[0];
            if(nums.size() == 2) return max(nums[0], nums[1]);
            int result1 = robResult(nums, 0, nums.size() - 2); //情況二
            int result2 = robResult(nums, 1, nums.size() - 1); //情況三
            return max(result1, result2);
    }
    int robResult(vector<int>& nums, int start, int end) {
        vector<int> dp (nums.size(), 0);
        dp[start] = nums[start];
        dp[start + 1] = max(nums[start], nums[start + 1]);
        for(int i = start + 2; i < nums.size(); i++) {
            dp[i] = max(dp[i - 1], dp[i - 2] + nums[i]);
        }
        return dp[end];
    } 
};

 

337.打家劫舍III - 實作

思路

  1. 確定傳入值與返回值
    1. 傳入值: treenode
    2. 返回值: dp數組
  2. dp數組定義
    1. 長度為二的數組,下標為0代表不偷該節點的最大金額,下標為1代表偷該節點的最大金額
  3. 確認終止條件
    1. 假設遇到空節點,返回{0, 0},代表偷與不偷都為0
  4. 確定樹的遍歷順序
    1. 後序遍歷,因為需要左右子樹的值來協助判斷
  5. 單層遞迴的邏輯
    1. 偷當前節點,左右孩子都不能偷,va1 = cur→val + left[0] + right[0]
    2. 不偷當前節點,左右孩子都可以偷,就是偷最大的 val2 = max(left[0] + left[1]) + max(right[0], right[1]);
  6. 遞推公式 max(val1, val2)

Code

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    int rob(TreeNode* root) {
        vector<int> result = robTree(root);
        return max(result[0], result[1]);
    }
    vector<int> robTree(TreeNode* cur) {
        if (cur == NULL) return vector<int>{0, 0};
        vector<int> left = robTree(cur->left);
        vector<int> right = robTree(cur->right);

        int val1 = cur->val + left[0] + right[0];
        int val2 = max(left[0],left[1]) + max(right[0], right[1]);
        return {val2, val1};
    }
};

 

總結

自己实现过程中遇到哪些困难

今天的三題,第一題因為之前做背包做太久,一開始就有點亂槍打鳥的意味,第二題則是沒有想到分為三種狀況分別處理,第三題有點像是第二題的延伸,不過這是第一題在動態規畫中使用到樹的概念,理解不難,但要自己寫出來就會遇到很大的問題

今日收获,记录一下自己的学习时长

大約學習了2hr左右,今天的三題都算是比較好理解的,但是自己之前沒有做過,所以在做的過程中很卡,但所幸都有初步理解了。

相關資料

● 今日学习的文章链接和视频链接

第九章 动态规划part09

198.打家劫舍

视频讲解:动态规划,偷不偷这个房间呢?| LeetCode:198.打家劫舍_哔哩哔哩_bilibili

https://programmercarl.com/0198.打家劫舍.html

213.打家劫舍II

视频讲解:动态规划,房间连成环了那还偷不偷呢?| LeetCode:213.打家劫舍II_哔哩哔哩_bilibili

https://programmercarl.com/0213.打家劫舍II.html

337.打家劫舍III

视频讲解:动态规划,房间连成树了,偷不偷呢?| LeetCode:337.打家劫舍3_哔哩哔哩_bilibili

https://programmercarl.com/0337.打家劫舍III.html

代码随想录】【算法训练营】【第45】 [198]打家劫舍 [213]打家劫舍II [337]打家劫舍III 思路及算法思维,指路。目来自。day 45,周五,坚持不了一点~ 阅读详情

相关推荐

代码随想录-算法训练营day47(动态规划09:打家劫舍,打家劫舍2,打家劫舍3)

动态规划09:打家劫舍

weixin_61931006的博客 636

@ 代码随想录算法训练营第8周(C语言|Day51(动态规划

打家劫舍。两种打家劫舍。二叉树加动态规划

fu1034810010的博客 951

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

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

a6666999d的博客 774

代码随想录算法训练营 Day39 动态规划打家劫舍

成环问解决,1. 去掉头尾链接看作线性数组解决,2. 考虑首元素不考虑尾元素,3. 只考虑尾元素。如果当前房价偷了,前一个不能偷,如果当前房价没偷,可以考虑偷不偷之前房。3. 二叉树的单层递归逻辑:按照后序遍历,将结果从叶子往根传递。表示不偷当前节点与偷当前节点,规定 0 表示不偷 1 表示偷。D. 遍历顺序跟随树的后序遍历(将结果逐个返回上一个节点),表示 dp 时打劫前 i 房子最大金币,前一个房子是。DP 流程推导,从叶子结点开始,如果给出两个 res。res 1 偷当前节点,那就取子节点不偷。

weixin_43679621的博客 403

代码随想录算法训练营第四十四| 139. 单词拆分、 56. 携带矿石资源(第八期模拟笔试)、198. 打家劫舍213. 打家劫舍 II337. 打家劫舍 III、121. 买卖股票的最佳时机

给你一个字符串s和一个字符串列表wordDict作为字典。如果可以利用字典中出现的一个或多个单词拼接出s则返回true。不要求字典中出现的单词全部都使用,并且字典中的单词可以重复使用。true返回 true 因为 "leetcode" 可以由 "leet" 和 "code" 拼接成。true返回 true 因为 "applepenapple" 可以由 "apple" "pen" "apple" 拼接成。注意,你可以重复使用字典中的单词。

913

代码随想录-算法训练营day47【动态规划09:打家劫舍打家劫舍II打家劫舍III

代码随想录-算法训练营day47【动态规划09:打家劫舍打家劫舍II打家劫舍III

upward 507

leetcode 56合并区间

这道你可以把它压缩成一个非常好记的思路:先排序,再逐个比较;能合并就扩右边界,不能合并就加入答案。具体来说,先用: 把所有区间按照左端点从小到大排序。排序之后,我们只需要拿“当前区间”和 里最后一个已经合并好的区间比较。如果: 说明前一个区间的右端点比当前区间左端点还小,二者没有重叠: 所以直接: 如果不满足: 那就说明: 两个区间重叠,例如: 此时左端点不用动,只需要把右端点扩大: 所以整道可以记成: 这道容易忘的函数/语法 含义:对整个 排序。对于:

qq_63176310的博客 224

LeetCode 1. 两数之和 | 从暴力枚举到哈希表最优解 + 空间换时间思想全复盘

文章摘要 目要求在数组中找到两数之和等于目标值的下标。核心思路是优化查找效率: 暴力法:双重循环枚举所有数对,时间复杂度O(n²),效率低但易实现。 哈希表优化:利用哈希表O(1)查找特性,遍历时存储已访问元素,每次计算差值并查询,时间复杂度降至O(n)。关键细节是先查后存,避免自匹配。 代码实现:哈希表法通过一次遍历完成,空间换时间,边界处理需注意空数组和不足两元素的情况。 常见错误:内层循环起始点、哈希表键值设计、立即返回结果等易错点需警惕。 面试要点:优先选择哈希表解法,解释与暴力法的差异,强调时间

yc2284238579的博客 229

算法日常・每日--<BFS>4

目摘要: 给定一个由'X'和'O'组成的矩阵,要求捕获所有被'X'完全包围的'O'区域(即不与边界连通的区域),并将其替换为'X'。解法核心是逆向处理: 标记边界连通区域:遍历矩阵四边,对边界上的'O'进行BFS/DFS,标记所有与之连通的'O'为临时符号(如'.'),表示这些区域未被包围。 批量修改:遍历整个矩阵,将未被标记的'O'(被包围的)改为'X',同时恢复标记的'.'为'O'。 示例: 输入: [['X','X','X','X'], ['X','O','O','X'], ['X','X','O'

2503_92261635的博客 245

百日算法修炼 · Day 10

本文介绍了8个算法练习,涵盖链表、栈、队列和递归等核心数据结构与操作。主要内容包括:反转单链表(指针修改顺序)、删除指定节点(虚拟头节点技巧)、双端队列模拟栈和队列、环形数组队列实现、O(1)获取最小值的栈设计、两个栈实现队列(延迟倒数据)、两个队列实现栈(保留最后一个元素),以及递归求解区间最大值(分治思想)。每个练习都强调关键思维:指针操作需先保存后继、数据结构可以互相模拟、递归要拆解大问为小问。建议先独立完成练习再对照参考答案,重点关注指针顺序、状态维护和问分解能力。

linux_hzh的博客 595

10.LeetCode算法讲解--滑动窗口--最大连续为一的个数

利用滑动窗口解决最大连续1的个数

Jammy_1的博客 195

问答大模型技术方案算法实现-RAPTOR树构建算法与BEG集成使用

算法核心特点 递归聚类:逐层对文档块进行聚类,构建层次结构摘要生成:为每个聚类生成摘要,捕获语义信息展开树检索:将所有节点展开,直接进行向量检索层次化检索:从根节点开始,逐层深入检索灵活聚类:支持层次聚类和基于阈值的聚类自适应:根据节点数量动态调整树结构可扩展:支持自定义摘要生成器和检索策略

qq_42773521的博客 187

环中最长子串字符成环找偶数O

如果 ‘o’ 出现的次数为奇数,则只能通过去掉一个字符(任意字符)来使得剩下的子字符串中的 ‘o’ 出现次数变为偶数。如果总共的 ‘o’ 个数已经是偶数,那么从字符串的任意位置开始到任意位置结束的子字符串,也一定能找到包含偶数次 ‘o’ 的最长子串,这个子串就是原字符串本身。最长子字符串是 “oxdolxl”,由于是首尾连接在一起的,所以最后一个 ‘x’ 和开头的 ‘l’是连接在一起的,此字符串包含 2 个’o’。如果 ‘o’ 出现的次数为偶数,那么整个字符串就符合目的要求:即包含偶数次的 ‘o’。

KevinChen2019的博客 192

AI辅助芯片制造:算法与工程化落地

《国产DRAM龙头长鑫科技上市创纪录,AI技术重塑芯片制造新范式》 国产DRAM龙头企业长鑫科技7月27日登陆科创板,创下3.31万亿元市值,成为A股"一哥"。作为大陆唯一实现DRAM大规模量产的IDM企业,长鑫科技标志着国产存储产业的重要突破。随着AI算力需求激增,DRAM市场迎来高速发展期。AI技术正在深度改变芯片制造模式,在工艺仿真、缺陷检测、设备维护等环节发挥关键作用,显著提升良率和效率。长鑫科技高管推荐的新书《AI辅助芯片制造:算法与工程化落地》系统解析了AI赋能半导体制造的实战方案

weixin_43178406的博客 3797

hot100-70.爬楼梯

dp数组初始化:dp[n+1];

2302_78497251的博客 40

算法武林谱:四大排序神功与二分寻宝术全解》

本文生动介绍了五大经典算法,通过趣味名称形象展现原理:1.快速排序(标杆劈叉法)- 分治思想,选标杆分区排序,平均O(nlogn);2.堆排序(金字塔淘汰赛)- 大顶堆构建与调整,稳定O(nlogn);3.归并排序(百川归海法)- 分治合并有序子数组,稳定O(nlogn)但需额外空间;4.希尔排序(缩步插缝法)- 改进插入排序,按步长分组排序;5.二分查找(折半寻宝术)- 有序数组折半查找,O(logn)高效。各算法均提供核心思想、步骤、复杂度分析和C++实现代码,可直接编译运行。

c23856的博客 373

S 曲线加减速算法完整详解(C# 原生实现,无第三方库)

S 曲线加减速是工业运动控制核心轨迹规划算法,相比梯形曲线,依靠约束加加速度 Jerk 实现加速度连续变化,有效消除机械冲击与振动。本文完整讲解七段式 S 曲线原理、阶段推演、时间预规划逻辑,剖析短行程自动裁剪等工程难点。提供无第三方依赖原生 C# 完整实现,内置运动状态机,支持正反方向运动,基于解析多项式实时求解位置、速度、加速度,无积分累积误差。代码可直接用于伺服上位机、模组轨迹发生器,亦可精简移植嵌入式平台。同时对比算法优劣与适用场景,适合工控开发、伺服调试、嵌入式运动算法学习者参考。

工业上位机开发工程师,专注C#底层算法与工控仪器开发。从零手写信号滤波、曲线拟合、机器视觉、排序与密码学哈希,纯原生实现零第三方库,附数学推导与可编译源码,可移植STM32/PLC。 927

Tokenization(分词算法):一切大语言模型的地基

本文深入解析了Tokenization(分词算法)这一大语言模型的基础技术。Tokenization将原始文本切分为模型可处理的子词单元并映射为数字ID,是模型理解文本的第一步。

2301_80194949的博客 185

STM32N6运行3A音频算法方法

STM32N6提供三种3A音频算法实现方案:1)利用Cortex-M55内核的Helium技术运行传统算法,支持800MHz主频和150条DSP指令;2)通过600GOPS NPU加速AI降噪等复杂算法;3)采用CPU+NPU混合架构实现最优性能。ST提供完整的开发工具链(STM32Cube.AI/X-CUBE-AI)和音频示例项目(STM32N6-GettingStarted-Audio),支持开发者灵活选择传统DSP处理、AI加速或混合方案。该芯片兼具800MHz主频CPU和专用NPU,能高效处理AGC

2401_89373706的博客 142
上一篇: 代碼隨想錄算法訓練營|第四十九天|139.单词拆分、关于多重背包、背包问题总结。刷题心得(c++)
下一篇: 代碼隨想錄算法訓練營|第五十一天|121. 买卖股票的最佳时机、122.买卖股票的最佳时机II。刷题心得(c++)
RVLIN
博客等级 码龄5年 104粉丝 · 53原创
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值