动态规划相关题目总结

221.最大正方形

设dp[i][j]为以点(i, j)为右下角的正方形最大边长,多画画图模拟模拟可以发现递推式dp[i][j] = min(dp[i][j-1], dp[i-1][j-1], dp[i-1][j])+1。

class Solution {
public:int maximalSquare(vector<vector<char>>& matrix) {int n = matrix.size(), m = matrix[0].size(), res = 0;vector<vector<int>> dp(n, vector<int>(m));for(int i = 0; i < n; i++)for(int j = 0; j < m; j++){if(matrix[i][j] == '0') dp[i][j] = 0;else{if(i-1 < 0 || j-1 < 0) dp[i][j] = 1;else{int mn = 0x3f3f3f3f;mn = min(mn, dp[i][j-1]);mn = min(mn, dp[i-1][j-1]);mn = min(mn, dp[i-1][j]);dp[i][j] = mn+1;}}res = max(res, dp[i][j]);}return res*res;}
};

53.最大子数组和

经典dp,设dp[i]为以nums[i]结尾的最大子数组和,考虑是否与nums[i-1]结尾的最大子数组结合,如果dp[i-1] < 0那肯定不结合,反之应该结合。

class Solution {
public:int maxSubArray(vector<int>& nums) {int last = nums[0], res = nums[0];for(int i = 1; i < nums.size(); i++){last = max(0, last)+nums[i];res = max(last, res);}return res;}
};

300.最长递增子序列

两种做法,第一种就是普通的dp,设dp[i]为以nums[i]结尾的最长递增子序列长度,然后向前枚举子序列前一个数字,时间复杂度是O(n^2)。第二种做法利用二分查找,时间复杂度为O(nlogn)。

//O(n^2)写法
class Solution {
public:int lengthOfLIS(vector<int>& nums) {vector<int> dp(nums.size());int res = 0;for(int i = 0; i < nums.size(); i++){dp[i] = 1;for(int j = 0; j < i; j++)if(nums[j] < nums[i]) dp[i] = max(dp[i], dp[j]+1);res = max(res, dp[i]);}return res;}
};
//O(nlogn)写法
class Solution {
public:int lengthOfLIS(vector<int>& nums) {vector<int> a(nums.size()+1, 0x3f3f3f3f);for(int i = 0; i < nums.size(); i++){int idx = lower_bound(a.begin(), a.end(), nums[i])-a.begin();a[idx] = nums[i];}return lower_bound(a.begin(), a.end(), 0x3f3f3f3f)-a.begin();}
};

32.最长有效括号

设dp[i]为以第i个括号结尾的最长有效括号串,如果第i个括号是左括号那dp[i]肯定是0,如果如果第i个括号是右括号那需要根据上一个括号分类讨论,若s[i-1]是左括号,那s[i-1]和s[i]正好凑成一对,此时dp[i] = dp[i-2]+2,若s[i-1]是右括号,那dp[i-1]就是该右括号最长有效括号长度,i-dp[i-1]就是该有效括号串的左端点,i-dp[i-1]-1的位置如果是个右括号,那它不能与i位置的右括号匹配,此时dp[i] = 0,如果i-dp[i-1]-1的位置是左括号,那它可以与i位置的右括号匹配,此时dp[i] = dp[i-1]+2+dp[i-dp[i-1]-2]。

class Solution {
public:int longestValidParentheses(string s) {s = " "+s;int n = s.size();vector<int> dp(n);int mx = 0;for(int i = 1; i < n; i++){if(s[i] == '(') continue;if(i >= 2){if(s[i-1] == '(') dp[i] = dp[i-2]+2;else{if(i-dp[i-1]-1 >= 1 && s[i-dp[i-1]-1] == '(') dp[i] = dp[i-1]+2+dp[i-dp[i-1]-2];}}mx = max(mx, dp[i]);}return mx;}
};

322.零钱兑换

设dp[i][j]表示只使用前i种货币,恰好凑到j元所需要的最少货币数。状态转移的时候考虑是否使用第i种货币,不使用的话就是dp[i-1][j],使用的话就是dp[i][j-coins[i]]+1,二者取最小值就行了。

class Solution {
public:int coinChange(vector<int>& coins, int amount) {int n = coins.size(), m = amount+1;vector<vector<int>> dp(n, vector<int>(m));for(int i = 0; i < m; i++)if(i%coins[0] == 0) dp[0][i] = i/coins[0];else dp[0][i] = 0x3f3f3f3f;for(int i = 0; i < n; i++) dp[i][0] = 0;for(int i = 1; i < n; i++)for(int j = 0; j < m; j++){dp[i][j] = dp[i-1][j];if(j >= coins[i])dp[i][j] = min(dp[i][j], dp[i][j-coins[i]]+1);}return dp[n-1][m-1]!=0x3f3f3f3f?dp[n-1][m-1]:-1;}
};

1143.最长公共子序列

设dp[i][j]表示考虑串1前i位以及串2前j位的最长公共子序列,如果串1的第i位和串2的第j位恰好相等,那就dp[i][j] = dp[i-1][j-1]+1,否则dp[i][j] = max(dp[i-1][j], dp[i][j-1])。

class Solution {
public:int longestCommonSubsequence(string text1, string text2) {int n = text1.size(), m = text2.size();vector<vector<int>> dp(n, vector<int>(m));bool flag = false;for(int i = 0; i < m; i++){if(text1[0] == text2[i]) flag = true;if(flag) dp[0][i] = 1;}flag = false;for(int i = 0; i < n; i++){if(text1[i] == text2[0]) flag = true;if(flag) dp[i][0] = 1;}for(int i = 1; i < n; i++)for(int j = 1; j < m; j++){if(text1[i] == text2[j]) dp[i][j] = dp[i-1][j-1]+1;dp[i][j] = max(dp[i][j], dp[i-1][j]);dp[i][j] = max(dp[i][j], dp[i][j-1]);}return dp[n-1][m-1];}
};

121.买卖股票的最佳时机

维护一个前缀最小值或者后缀最大值就行了。

class Solution {
public:int maxProfit(vector<int>& prices) {vector<int> mn(prices.size());int mx = 0;for(int i = 0; i < prices.size(); i++){mn[i] = prices[i];if(i > 0) mn[i] = min(mn[i-1], mn[i]);mx = max(mx, prices[i]-mn[i]);}return mx;}
};

72.编辑距离

设dp[i][j]表示将串1的前i位变为串2前j位所需最少操作数,状态转移就是考虑最后一次执行的是什么操作,如果最后一次是删除,那就对应dp[i][j] = dp[i-1][j]+1,如果最后一次是添加,那就对应dp[i][j] = dp[i][j-1]+1,如果最后一次是修改,那就是dp[i][j] = dp[i-1][j-1]+1,当然如果本身第i位和第j位就相等,那dp[i][j] = dp[i-1][j-1],这四种情况取最小值。

class Solution {
public:int minDistance(string word1, string word2) {word1 = "!"+word1;word2 = "!"+word2;int n = word1.size(), m = word2.size();vector<vector<int>> dp(n, vector<int>(m));for(int i = 0; i < m; i++)dp[0][i] = i;for(int i = 0; i < n; i++)dp[i][0] = i;for(int i = 1; i < n; i++)for(int j = 1; j < m; j++){dp[i][j] = min(dp[i][j-1], min(dp[i-1][j], dp[i-1][j-1]))+1;if(word1[i] == word2[j]) dp[i][j] = min(dp[i][j], dp[i-1][j-1]);}return dp[n-1][m-1];}
};

70.爬楼梯

经典入门dp题目。

class Solution {
public:int climbStairs(int n) {vector<int> dp(n+5);dp[1] = 1, dp[2] = 2;for(int i = 3; i <= n; i++)dp[i] = dp[i-1]+dp[i-2];return dp[n];}
};

122.买卖股票的最佳时机 II

设dp[i][0]表示在第i天手上没有股票时的钱,dp[i][1]表示在第i天手上有股票时的钱,状态转移的话如果当天没有股票那说明可能是今天卖出去了,也可能是昨天手上就没股票继承过来了,所以dp[i][0] = max(dp[i-1][0], dp[i-1][1]+prices[i]),然后如果当天有股票那说明可能是今天刚买,也可能是昨天手上就有股票继承过来了,所以dp[i][1] = max(dp[i-1][1], dp[i-1][0]-prices[i])。

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

198.打家劫舍

设dp[i]表示前i个位置拿到的钱,状态转移的时候考虑是否拿第i个位置的钱,如果拿的话那dp[i] = dp[i-2]+nums[i],如果不拿的话dp[i] = dp[i-1],二者取一个最大值就行了。

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

139.单词拆分

一开始想的是把单词都存到哈希表里,然后遍历字符串,过程中把字符累加到临时字符串中,只要临时字符串在哈希表中出现就置空,看最后临时字符串是否为空。但是这个方法没法通过样例s = "aaaaaaa", wordDict = ["aaa", "aaaa"]。

设dp[i]表示前i个字符能否凑出来,状态转移就是枚举最后一个单词,时间复杂度接近O(n^2)。

class Solution {
public:bool wordBreak(string s, vector<string>& wordDict) {s = " "+s;int n = s.size();vector<bool> dp(n);dp[0] = true;for(int i = 0; i < n; i++){for(int j = 0; j < wordDict.size(); j++){if(i >= wordDict[j].size() && s.substr(i-wordDict[j].size()+1, wordDict[j].size()) == wordDict[j])dp[i] = max(dp[i], dp[i-wordDict[j].size()]);}}return dp[n-1];}
};

64.最小路径和

对于(i, j)要么从(i-1, j)过来,要么从(i, j-1)过来,根据这个进行状态转移。

class Solution {
public:int minPathSum(vector<vector<int>>& grid) {int n = grid.size(), m = grid[0].size();vector<vector<int>> dp(n, vector<int>(m));for(int i = 0; i < n; i++)for(int j = 0; j < m; j++){int mn = 0x3f3f3f3f;if(i > 0) mn = min(mn, dp[i-1][j]);if(j > 0) mn = min(mn, dp[i][j-1]);if(mn == 0x3f3f3f3f) mn = 0;dp[i][j] = grid[i][j]+mn;}return dp[n-1][m-1];}
};

718.最长重复子数组

设dp[i][j]表示串1前i位和串2前j位最长公共子串长度,如果对应的两个位置值不同那就置0,否则dp[i][j] = dp[i-1][j-1]+1。

class Solution {
public:int findLength(vector<int>& nums1, vector<int>& nums2) {int n = nums1.size(), m = nums2.size();vector<vector<int>> dp(n, vector<int>(m));int mx = 0;for(int i = 0; i < m; i++){dp[0][i] = nums1[0]==nums2[i];mx = max(mx, dp[0][i]);}for(int i = 0; i < n; i++){dp[i][0] = nums1[i]==nums2[0];mx = max(mx, dp[i][0]);}for(int i = 1; i < n; i++)for(int j = 1; j < m; j++){if(nums1[i] == nums2[j]) dp[i][j] = dp[i-1][j-1]+1;mx = max(mx, dp[i][j]);}return mx;}
};

128.最长连续序列

两种做法,第一种是用哈希+并查集,首先把数组中的数字都保存在哈希表中,之后遍历一遍数组,检查nums[i]-1是否在哈希表中,如果也存在的话那就用并查集把两个集合合并,同时可以开一个数组维护一下每个连通块大小,最后答案就是最大连通块的大小。

第二种做法是哈希+遍历,思路更简单一些,还是把数组中的数字都保存在哈希表中,然后遍历一遍原数组,当某个元素是所在连续序列中最小的一个时,直接从它的数值递增来求该序列长度。

//哈希+并查集写法
class Solution {
public:vector<int> fa;int find(int x){if(fa[x] == x) return x;return fa[x] = find(fa[x]);}int longestConsecutive(vector<int>& nums) {fa.resize(nums.size());vector<int> sz(nums.size());unordered_map<int, int> mp;for(int i = 0; i < nums.size(); i++)fa[i] = i, sz[i] = 1, mp[nums[i]] = i;for(int i = 0; i < nums.size(); i++){if(mp.count(nums[i]-1)){int r1 = find(mp[nums[i]]), r2 = find(mp[nums[i]-1]);if(r1 == r2) continue;if(sz[r1] > sz[r2]){sz[r1] += sz[r2];fa[r2] = r1;}else{sz[r2] += sz[r1];fa[r1] = r2;}}}int res = 0;for(int i = 0; i < nums.size(); i++)res = max(sz[i], res);return res;}
};
//哈希+遍历写法
class Solution {
public:int longestConsecutive(vector<int>& nums) {unordered_map<int, int> mp;for(int i = 0; i < nums.size(); i++)mp[nums[i]] = 1;int res = 0;for(auto x:mp){if(!mp.count(x.first-1)){int len = 0;while(mp.count(x.first+len)) len++;res = max(res, len);}}return res;}
};

62.不同路径

设dp[i][j]为从起点到(i, j)的路径数,状态转移根据上一步的位置,dp[i][j] = dp[i-1][j]+dp[i][j-1]。

class Solution {
public:int uniquePaths(int m, int n) {swap(m, n);vector<vector<int>> dp(n, vector<int>(m));for(int i = 0; i < n; i++)for(int j = 0; j < m; j++){if(i == 0 && j == 0) dp[i][j] = 1;if(i > 0) dp[i][j] += dp[i-1][j];if(j > 0) dp[i][j] += dp[i][j-1];}return dp[n-1][m-1];}
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/690239.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

一文搞懂设计模式—适配器模式

本文已收录至Github&#xff0c;推荐阅读 &#x1f449; Java随想录 微信公众号&#xff1a;Java随想录 文章目录 使用场景实现方式类适配器实现对象适配器实现 优缺点总结 适配器模式&#xff08;Adapter Pattern&#xff09;属于结构型模式&#xff0c;用于将一个类的接口转…

《剑指 Offer》专项突破版 - 面试题 45 和 46 : 二叉树最低层最左边的值和二叉树的右侧视图(C++ 实现)

目录 面试题 45 : 二叉树最低层最左边的值 面试题 46 : 二叉树的右侧视图 面试题 45 : 二叉树最低层最左边的值 题目&#xff1a; 如何在一棵二叉树中找出它最低层最左边节点的值&#xff1f;假设二叉树中最少有一个节点。例如&#xff0c;在下图所示的二叉树中最低层最左边…

Codeforces Round 924 (Div. 2)题解(A-D)

A - Rectangle Cutting 链接&#xff1a;A - Rectangle Cutting 思路 考虑横边和纵边&#xff0c;若为偶数&#xff0c;则从中间分开&#xff0c;重新组合为一个长方形&#xff0c;检测是否与原来的长方形一致。 代码 #include <bits/stdc.h> using namespace std;i…

logback实践

1:日志区分环境 2:debug info warn error日志文件不一样 3: 文件滚动日志 4:启动可带参数 --spring.profiles.activedev --log.levelinfo 5:可从配置文件中获取上下文参数 logback-spring.xml 放在 classpath 下面 <configuration scan"false" scanPer…

探秘OpenAI的神奇之作:Sora技术揭秘

探秘OpenAI的神奇之作&#xff1a;Sora技术揭秘 1. 引言 在当今科技快速发展的时代&#xff0c;人工智能&#xff08;AI&#xff09;正日益成为各个领域的关键技术。而在人工智能领域中&#xff0c;OpenAI公司一直以来都扮演着重要的角色。他们的最新创新——Sora技术&#x…

基于python的遥感影像灰色关联矩阵纹理特征计算

遥感影像纹理特征是描述影像中像素间空间关系的统计特征&#xff0c;常用于地物分类、目标识别和变化检测等遥感应用中。常见的纹理特征计算方式包括灰度共生矩阵&#xff08;GLCM&#xff09;、灰度差异矩阵&#xff08;GLDM&#xff09;、灰度不均匀性矩阵&#xff08;GLRLM&…

常见面试题:TCP的四次挥手和TCP的滑动窗口

说一说 TCP 的四次挥手。 挥手即终止 TCP 连接&#xff0c;所谓的四次挥手就是指断开一个 TCP 连接时。需要客户端和服务端总共发出四个包&#xff0c;已确认连接的断开在 socket 编程中&#xff0c;这一过程由客户端或服务端任意一方执行 close 来触发。这里我们假设由客户端…

unity学习(29)——GameInfo角色信息

1.把GameInfo.cs PlayerModel.cs Vector3.cs Vector4.cs PlayerStateConstans.cs GameState.cs依次粘到model文件夹中&#xff0c;此时项目没有错误&#xff0c;如下图所示&#xff1b; 对应处所修改的代码如下&#xff1a; case LoginProtocol.LOGIN_SRES://1 {Debug.Log(&qu…

考研查分,别再只知道研招网了!

查分时间基本已经敲定在2月26日左右了。倒计时7天&#xff01;每年查询分数的时候经常因为查询人数太多&#xff0c;进不去研招网&#xff0c;还有哪些方法可以查询分数呢&#xff1f; 我为大家整理了四种常用的查成绩方式&#xff0c;附带部分已公布查分时间院校名单。 一、…

Java学习心得感悟

在我踏入Java学习的道路之前&#xff0c;我对编程只是一知半解&#xff0c;对于代码的世界充满了好奇和向往。然而&#xff0c;当我真正开始学习Java时&#xff0c;我才意识到&#xff0c;学习Java不仅仅是学习一门编程语言&#xff0c;更是一种思维方式和解决问题的能力的培养…

【AI视野·今日Sound 声学论文速览 第四十九期】Wed, 17 Jan 2024

AI视野今日CS.Sound 声学论文速览 Wed, 17 Jan 2024 Totally 23 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Sound Papers From Coarse to Fine: Efficient Training for Audio Spectrogram Transformers Authors Jiu Feng, Mehmet Hamza Erol, Joon Son Chung,…

Pandas Series Mastery: 从基础到高级应用的完整指南【第83篇—Series Mastery】

Pandas Series Mastery: 从基础到高级应用的完整指南 Pandas是Python中一流的数据处理库&#xff0c;它为数据科学家和分析师提供了强大的工具&#xff0c;简化了数据清理、分析和可视化的流程。在Pandas中&#xff0c;Series对象是最基本的数据结构之一&#xff0c;它为我们处…

Spring Security基础学习

一、SpringSecurity框架简介 二、SpringSecurity入门案例 三、SpringSecurity Web权限方案 四、SpringSecurity微服务权限方案 五、SpringSecurity原理总结

Unity中的Lerp插值的使用

Unity中的Lerp插值使用 前言Lerp是什么如何使用Lerp 前言 平时在做项目中插值的使用避免不了&#xff0c;之前一直在插值中使用存在误区&#xff0c;在这里浅浅记录一下。之前看的博客或者教程还多都存在一个“永远到达不了&#xff0c;只能无限接近”的一个概念。可能是之前脑…

open3d DBSCAN 聚类

DBSCAN 聚类 一、算法原理1.密度聚类2、主要函数 二、代码三、结果四、相关数据 一、算法原理 1.密度聚类 介绍 基于密度的噪声应用空间聚类(DBSCAN)&#xff1a;是一种无监督的ML聚类算法。无监督的意思是它不使用预先标记的目标来聚类数据点。聚类是指试图将相似的数据点分…

微信美容预约小程序开发实战教程,快速掌握开发技巧

如果你想开发一个美容美发小程序&#xff0c;以下是一个搭建指南&#xff0c;供你参考。 1. 使用第三方制作平台 首先&#xff0c;你需要使用一个第三方制作平台&#xff0c;如乔拓云网。在该平台上&#xff0c;你需要注册并登录&#xff0c;然后点击【轻应用小程序】进入设计…

springboot201基于SpringBoot的论坛系统设计与实现

论坛系统设计与实现 摘 要 如今的时代&#xff0c;是有史以来最好的时代&#xff0c;随着计算机的发展到现在的移动终端的发展&#xff0c;国内目前信息技术已经在世界上遥遥领先&#xff0c;让人们感觉到处于信息大爆炸的社会。信息时代的信息处理肯定不能用之前的手工处理这…

LineageOS:Android开源手机操作系统的未来之路

LineageOS&#xff1a;开源手机操作系统的未来之路 1. 引言 当前移动技术的迅猛发展使得手机操作系统变得至关重要。在众多操作系统中&#xff0c;LineageOS作为一款备受推崇的开源手机操作系统&#xff0c;其在过去几年中取得了显著的发展。本文将介绍LineageOS作为一款开源…

2009-2023年上市公司华证ESG评级得分数据

2009-2023年上市公司华证ESG评级得分数据 1、时间&#xff1a;2009-2023年 2、来源&#xff1a;华证ESG评级 3、范围&#xff1a;A股上市公司 4、指标&#xff1a;股票代码、证券简称、年份、ESG得分-年均值、ESG得分-年中位数 5、方法说明&#xff1a;将华证ESG评级进行赋…

力扣题目训练(16)

2024年2月9日力扣题目训练 2024年2月9日力扣题目训练530. 二叉搜索树的最小绝对差541. 反转字符串 II543. 二叉树的直径238. 除自身以外数组的乘积240. 搜索二维矩阵 II124. 二叉树中的最大路径和 2024年2月9日力扣题目训练 2024年2月9日第十六天编程训练&#xff0c;今天主要…