leetcode 经典动态规划DP算法题目(思路、方法、code)

leetcode买卖股票问题(思路、方法、code) 一文解决Leetcode买卖股票问题 对于前3个问题,均采用了比较巧妙的解法。由于第4个问题具有非常强的泛型,因此采用了DP,第4个问题的dp如果理解的话,实际上只需要稍加修改状态便可以用该dp思路应用于所有的6个题中。在后两个问题便是基于该思路用dp解决的。 文章目录一文解决Leetcode买卖股票问题[121. 买卖股票的最佳时机](https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/)[122. 买卖股票的最佳时机 II]( 阅读详情

leetcode 经典动态规划DP算法题目(思路、方法、code)

动态规划最重要的在于设计DP数组,找到相应的动态转移方程

70. 爬楼梯

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?

**注意:**给定 n 是一个正整数。

分析:这个问题,可以看青蛙跳台阶(递归与数学归纳),实际上就是斐波那契数列的变体

在上述中,采用了递归或者正向遍历的方法,实际上动态规划就是一种正向遍历的方法。如果采用递归时,由于f(n)=f(n-1)+f(n-2),故直接递归即可,但是仔细思考,如果用该方法,计算f(n-1)时计算了f(n-2),而计算f(n)时又计算了f(n-2),因此存在大量的重复计算。故在此便考虑用一个数组存储对应的函数值,这便是动态规划思想。

令f(n)表示到达n阶的楼顶的方法数,则f(n)=f(n-1)+f(n-2),正向计算即可。

class Solution {
   
   
public:
    int climbStairs(int n) 
    {
   
   
         vector<int> dp(n+1);
         dp[0]=1;dp[1]=1;
         for(int i=2;i<=n;i++)
            dp[i]=dp[i-1]+dp[i-2];
        return dp[n];
    }
};
198. 打家劫舍

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

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

示例 1:
输入: [1,2,3,1]
输出: 4
解释: 偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。
     偷窃到的最高金额 = 1 + 3 = 4 。

示例 2:
输入: [2,7,9,3,1]
输出: 12
解释: 偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9),接着偷窃 5 号房屋 (金额 = 1)。
     偷窃到的最高金额 = 2 + 9 + 1 = 12 。

分析:由于相邻的房间不能同时选择,因此在第k个房间时,有两种情况

  • 如果选取了第k个房间,说明第k-1个房间一定不能选,那说明这种情况的最大金额应该是前k-2个房间的最大金额加上第k个房间的金额
  • 如果没有选取第k个房间,说明这种情况的最大金额实际上就是前k-1个房间的最大金额
  • 因此,如果令 d p [ i ] dp[i] dp[i] 表示从0 到 $i $ 房间能盗窃的最高金额,动态转移方程则为 d p [ i ] = m a x ( d p [ i − 2 ] + a [ i ] , d p [ i − 1 ] ) dp[i]=max(dp[i-2]+a[i],dp[i-1]) dp[i]=max(dp[i−2]+a[i],dp[i−1]) ,其中 a [ i ] a[i] a[i]表示第i个房间的金额

根据此,可以遍历,最终结果应该为 d p [ n − 1 ] dp[n-1] dp[n−1]

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

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

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

示例 1:
输入: [2,3,2]
输出: 3
解释: 你不能先偷窃 1 号房屋(金额 = 2),然后偷窃 3 号房屋(金额 = 2), 因为他们是相邻的。

示例 2:
输入: [1,2,3,1]
输出: 4
解释: 你可以先偷窃 1 号房屋(金额 = 1),然后偷窃 3 号房屋(金额 = 3)。
     偷窃到的最高金额 = 1 + 3 = 4 。

分析:这个题与上一个题的区别在于,房屋是环形的,这意味着,第一个房间和最后一个房间不能同时偷窃。这就意味着,**将原来的问题转化为两个子问题:偷窃1 ~ n-1个房间的最大值以及偷窃 2~n 个房间的最大值。最终,取二者的最大值即为解。**因此可以对上一个问题进行两次dp即可。

class Solution {
   
   
public:
    int rob(vector<int>& nums) 
    {
   
   
        int length=nums.size();
        if(length==0) return 0;
        if(length==1) return nums[0];
        vector<int> dp(length+1);
        dp[0]=nums[0];
        dp[1]=max(nums[0],nums[1]);
        for(int i=2;i<length-1;i++) //先对前n-1进行DP
        {
   
   
            dp[i]=max(dp[i-2]+nums[i],dp[i-1]);
        }
        int result=dp[length-2]; //存储其值
        dp[0]=0;dp[1]=nums[1];
        for(int i=2;i<length;i++)  //对后n-1进行DP
        {
   
   
            dp[i]=max(dp[i-2]+nums[i],dp[i-1]);
        }
        //取最大值即可
        result=max(result,dp[length-1]);
        return result;
    }
};
337. 打家劫舍 III

在上次打劫完一条街道之后和一圈房屋后,小偷又发现了一个新的可行窃的地区。这个地区只有一个入口,我们称之为“根”。 除了“根”之外,每栋房子有且只有一个“父“房子与之相连。一番侦察之后,聪明的小偷意识到“这个地方的所有房屋的排列类似于一棵二叉树”。 如果两个直接相连的房子在同一天晚上被打劫,房屋将自动报警。

计算在不触动警报的情况下,小偷一晚能够盗取的最高金额。

示例 1:
输入: [3,2,3,null,3,null,1]

     3
    / \
   2   3
    \   \ 
     3   1

输出: 7 
解释: 小偷一晚能够盗取的最高金额 = 3 + 3 + 1 = 7.

示例 2:
输入: [3,4,5,1,3,null,1]

     3
    / \
   4   5
  / \   \ 
 1   3   1

输出: 9
解释: 小偷一晚能够盗取的最高金额 = 4 + 5 = 9.

分析:每个节点可选择偷或者不偷两种状态,根据题目意思,相连节点不能一起偷,因此父结点如果偷,则两个字节点就不能偷,父结点如果不偷,则子节点可以偷。注意这里说的是可以而不是一定,只需要父结点不偷的情况下两个子节点能够拿出最多的钱即可。因此有了递归的想法。

  • 当前节点选择不偷:当前节点能偷到的最大钱数 = 左孩子能偷到的最大钱 + 右孩子能偷到的最大钱
  • 当前节点选择偷:当前节点能偷到的最大钱数 = 左孩子选择自己不偷时能得到的钱 + 右孩子选择不偷时能得到的钱 + 当前节点的钱数
  • 考虑到在python中常用的返回多值的函数,在此处用了pair来存储结果,其中pair的第一个表示当前节点不偷获得的最大钱,pair的第二个表示当前节点偷的话获得的最大钱,根据此,便可以将上述逻辑轻松地表达出来。
class Solution {
   
   
public:
    int rob(TreeNode* root) 
	{
   
   
		pair<int,int> result=rob_helper(root);
		return max(result.first,result.second);
    }
    pair<int,int> rob_helper(TreeNode* root)
    {
   
   
    	pair<int,int> root_result;
    	pair<int,int> root_left;
    	pair<int,int> root_right;
    	if(root==NULL) return root_result;	
    	else
    	{
   
   
    		root_left=rob_helper(root->left);
    		root_right=rob_helper(root->right);
		}
			
  root_result.first=max(root_left.first,root_left.second)+max(root_right.first,root_right.second);
		root_result.second=root_left.first+root_right.first+root->val;
		return root_result;
	}
};
53. 最大子序和

给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

输入: [-2,1,-3,4,-1,2,1,-5,4],
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。

分析:

动态规划法:动态规划的关键,就是设置dp变量,找到动态转移方程

对于该题而言,由于需要找连续子数组,因此设置 d p dp dp变量时,必须考虑如何设置才能够将连续考虑在内。在此用 d p [ i ] dp[i]

LeetCode经典150题:大厂算法面试通关秘籍 算法与数据结构是计算机科学的核心基础,其中二分查找、动态规划等经典算法思想在工程实践中具有广泛应用价值。通过系统掌握这些算法原理,开发者能够有效解决数据处理、性能优化等实际问题。在技术面试场景中,LeetCode经典150题作为经过大厂实战检验的算法能力评估体系,覆盖了数组操作、树形结构、系统设计等高频考点。其中二分查找的变形应用和动态规划的降维技巧尤为关键,例如旋转数组查找和最长递增子序列等典型问题。合理运用滑动窗口、回溯等解题模式,配合三遍刷题法等科学训练方法,可以显著提升算法面试通过率。 阅读详情

相关推荐

直击高频编程考点:动态规划经典算法题总结

动态规划基本理解分析以及应用举例,同时给出高频笔试考题解法分析和代码展示验证(最大子序和、最长上升子序列、最长公共子序列、最大子数组乘积、分割整数的最大乘积、最长有效括号、不同路径、最小路径和、最大矩形、0-1背包问题、编辑距离、单词拆分、爬楼梯、打家劫舍、强盗抢劫环形街区、股票买卖问题、最佳买卖股票时机含冷冻期、找零钱的最少硬币数、从起点到终点的最小路径数等)

曾经“等你生日那天”都遥远得像未来,如今却可欢愉的挥手说“下个十年见” 5万+

leetcode题目分类

这份文档列出了leetcode几乎所有题目(大约134题)的分类以及难度指示,是刷leetcode的必备良品。现在leetcode总的题目数已经达到150题,所以有部分题目没有包含在这个文档中,但是——足够了。po主刷leetcode的时候参照了这份文档中的难度分级,从1开始刷到5,最终刷完150题。当然里面的题目难度分级对每个人来说都有一些不准确,因为不同人擅长的题目类型不同,但是即便这样也具有一定的指导意义。 找到这份东西也不容易,所以就盛惠1分~哈哈~

DP-LeetCode1143. 最长公共子序列(Python)

1、题目描述 2、代码详解 自下向上 class Solution(object): # Modify the original triangle, bottom-up def minimumTotal(self, triangle): """ :type triangle: List[List[int]] :rtype: int """ if not triangle: return for i in range(len(triangle) - 2, -

【Photoshop JSX脚本】强大的事件监听器脚本 - event_listener.jsx

新手第一次了解的事件监听一定是ScriptingListener.8bi插件,如果你对此插件有了基本运用,那么现在了解一款更方便的时间监听脚本event_listener.jsx。不再像ScriptingListener.8bi插件那样晦涩难懂。 1、准备event_listener.jsx文件到 F:\Program Files\Adobe Photoshop 2020\Presets\...

Greless的后花园 8208

【云迁移工具RDA】迁移常见问题

Agent无法正常启动,Linux系统提示“SMS.0201 Failed to start sms agent!”,Windows系统提示“SMS.0201 源端主机网络繁忙,无法连接api网关”。该问题通常是由于源端没有通公网,或者没有按照要求配置hosts,无法与iam或者sms通信导致。需要排查源端网络。1.登录源端服务器。2.检查源端是否能正常访问互联网,若无法访问,请处理后重新启动Agent。可参考弹性公网IP Ping不通检查源端的DNS,防火墙,安全组、本地网络等。

2404_89358774的博客 1486

Android OTA 升级实战指南:从原理到实现

本文详细解析了Android OTA升级的原理与实现方法,包括AB升级与Recovery升级的机制对比、OTA升级包制作流程以及应用层升级功能的实现。通过实战案例和常见问题排查指南,帮助开发者掌握Android系统无线升级技术,提升设备维护效率。

weixin_42652674的博客 200

Win11只读模式无法关闭的终极解决方案

通过以上方法,我们应该能够解决Windows 11中文件夹无法取消只读状态的问题。如果问题仍然存在,请确保你的账户具有足够的权限来修改文件夹属性,并考虑是否有其他安全软件或策略阻止了权限更改。在操作过程中,请务必小心谨慎,避免误操作导致数据丢失或系统损坏。希望本文能够帮助到大家!

mmoo_python的博客 1万+

QT西游回合制源码+java后台管理系统

这是一套回合制游戏源码,很适合学习。

renkai721的专栏 2536

国网DLT698.45协议——采集系统、数据交换(三)

物理层规定了通信单元或其他终端设备与多功能电表的通信接口,接口的物理与电气特性。常见的物理层传输方式有对于RS485、红外、载波通信等通信信道。将数据包装成可传输的帧格式。1、根据通信配置参数完成端口的初始化配置,通信状态初始化为准备接收状态,初始化相关计数器及缓冲区指针。2、链路层及控制子模块负责通信数据的收发控制,各类超时问题的处理。无通信数据接收时,定时初始化通信端口。3、完成协议帧的解析及应答。

一个bug是bug,多个bug能work 8052

【EB_Tresos专题】-01-EB Tresos导入工程

<--返回「Autosar_BSW高阶配置」总目录--> <--返回「Autosar_BSW高阶配置」专栏主页--> <--返回「个人博客」首页--> <--返回「Autosar_BSW高阶配置」总目录--> <--返回「Autosar_BSW高阶配置」专栏主页--> <--返回「个人博客」首页--> 结尾 ...

「汽车电子助手」的博客 6437

hwasan实例分析踩内存之一:camx进程stack tag-mismatch的三种解决方案

hwasan实例分析踩内存之一:camx进程stack tag-mismatch的三种解决方案。

1291

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

上一篇: leetcode 经典哈希表与字符串题目(思路、方法、code)
下一篇: leetcode 经典宽搜BFS深搜DFS题目(思路、方法、code)
coding丁
博客等级 码龄9年 383粉丝 147原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值