动态规划2

目录

121 买卖股票的最佳时机

打家劫舍

62 不同路径

64 最小路径和

53 最大子数组和 (动归 普通数组部分)

152 乘积最大子数组

300 最长递增子序列

1143 最长公共子序列

72 编辑距离


121 买卖股票的最佳时机

给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。

你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。

返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。

class Solution {public int maxProfit(int[] prices) {int len = prices.length;// dp[i][0]代表第i天持有股票的最大收益// dp[i][1]代表第i天不持有股票的最大收益int[][] dp = new int[len][2];//第一天持有股票,只能是第一天购入,收益为-pricesdp[0][0] = -prices[0];//第一天不持有股票,既没有购买,收益为0dp[0][1] = 0;for (int i = 1; i < len; i++) {//第i天持有,可能是前一天购入,或当天购入dp[i][0] = Math.max(dp[i - 1][0], -prices[i]);//第i天不持有,可能是前一天持有,今天售出或前一天也不持有(保持现状)dp[i][1] = Math.max(dp[i - 1][0] + prices[i], dp[i - 1][1]);}//本题中不持有股票状态所得金钱一定比持有股票状态得到的多!return dp[len - 1][1];}
}

打家劫舍

如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警

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

class Solution {public int rob(int[] nums) {// 考虑下标 i(包括 i)以内的房屋,最多可以偷窃的金额为 dp[i]。// 如果偷第i房间,那么dp[i] = dp[i - 2] + nums[i] 因为求的是能偷的最高金额,因此尽量不走空// 如果不偷第i房间,那么dp[i] = dp[i - 1] (只是考虑偷i-1不一定真的偷)// 然后dp[i]取最大值,即dp[i] = max(dp[i - 2] + nums[i], dp[i - 1]);// dp[0] 一定是 nums[0],dp[1]就是nums[0]和nums[1]的最大值if (nums.length == 1) return nums[0];int[] dp = new int[nums.length];dp[0] = nums[0];dp[1] = Math.max(dp[0], nums[1]);for (int i = 2; i < nums.length; i++) {dp[i] = Math.max(dp[i - 2] + nums[i], dp[i - 1]);}return dp[nums.length - 1]; //数组下标从0开始}}

62 不同路径

一个机器人位于一个 m x n网格的左上角 (起始点在下图中标记为 “Start” )。

机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。

问总共有多少条不同的路径?

class Solution {public int uniquePaths(int m, int n) {// dp[i][j] :表示从(0 ,0)出发,到(i, j) 有dp[i][j]条不同的路径。// dp[i][j] = dp[i - 1][j] + dp[i][j - 1]// dp[i][0],dp[0,j]一定都是1int[][] dp = new int[m][n];// 初始化for (int i = 0; i < m; i++) {dp[i][0] = 1;}for (int i = 0; i < n; i++) {dp[0][i] = 1;}for (int i = 1; i < m; i++) {for (int j = 1; j < n; j++) {dp[i][j] = dp[i - 1][j] + dp[i][j - 1];}}return dp[m - 1][n - 1];}
}

64 最小路径和

给定一个包含非负整数的 m x n 网格 grid ,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。

说明:每次只能向下或者向右移动一步。


不使用备忘录计数,更好理解

class Solution {public int minPathSum(int[][] grid) {int m = grid.length;int n = grid[0].length;int[][] dp = new int[m][n];dp[0][0] = grid[0][0];// 初始化第一行for (int j = 1; j < n; j++) {dp[0][j] = dp[0][j - 1] + grid[0][j];}// 初始化第一列for (int i = 1; i < m; i++) {dp[i][0] = dp[i - 1][0] + grid[i][0];}// 填充剩余格子for (int i = 1; i < m; i++) {for (int j = 1; j < n; j++) {dp[i][j] = Math.min(dp[i - 1][j], dp[i][j - 1]) + grid[i][j];}}return dp[m - 1][n - 1];}
}

53 最大子数组和 (动归 普通数组部分)

子数组是数组中的一个连续部分。

动规解法

class Solution {public int maxSubArray(int[] nums) {int n = nums.length;if (n == 0) return 0;int[] dp = new int[n];// base case// 第一个元素前面没有子数组dp[0] = nums[0];// 状态转移方程for (int i = 1; i < n; i++) {dp[i] = Math.max(nums[i], nums[i] + dp[i - 1]);}// 得到 nums 的最大子数组int res = Integer.MIN_VALUE;for (int i = 0; i < n; i++) {res = Math.max(res, dp[i]);}return res;}
}

152 乘积最大子数组

dp 数组是:dp[i] 记录以 nums[i] 为结尾的「最大子数组和」,从而写出状态转移方程。

这道题和 上一题的最大区别在于,要同时维护「以 nums[i] 结尾的最大子数组」和「以 nums[i] 结尾的最小子数组」,以便适配 nums[i] 可能为负的情况。

class Solution {public int maxProduct(int[] nums) {int n = nums.length;// 定义:以 nums[i] 结尾的子数组,乘积最小为 dp1[i]int[] dp1 = new int[n];// 定义:以 nums[i] 结尾的子数组,乘积最大为 dp2[i]int[] dp2 = new int[n];// base casedp1[0] = nums[0];dp2[0] = nums[0];// 状态转移方程  需要和 nums[i]比较 以nums[i]为结尾的数组//单独的 nums[i] 可能作为一个新的子数组。for (int i = 1; i < n; i++) {dp1[i] = min(dp1[i - 1] * nums[i], dp2[i - 1] * nums[i], nums[i]);dp2[i] = max(dp1[i - 1] * nums[i], dp2[i - 1] * nums[i], nums[i]); }// 遍历所有子数组的最大乘积,求最大值int res = Integer.MIN_VALUE;for (int i = 0; i < n; i++) {res = Math.max(res, dp2[i]);}return res;}int min(int a, int b, int c) {return Math.min(Math.min(a, b), c);}int max(int a, int b, int c) {return Math.max(Math.max(a, b), c);}
}

300 最长递增子序列

子数组一定是连续的,而子序列不一定是连续的。

子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。


dp 数组的定义:dp[i] 表示以 nums[i] 这个数结尾的最长递增子序列的长度。

那么 dp 数组中最大的那个值就是最长的递增子序列长度。

子数组一定是连续的,而子序列不一定是连续的。
class Solution {public int lengthOfLIS(int[] nums) {// dp[i] 表示以 nums[i] 这个数结尾的最长递增子序列的长度int[] dp = new int[nums.length];// base case:dp 数组全都初始化为 1Arrays.fill(dp, 1);//快慢指针for (int i = 0; i < nums.length; i++) {for (int j = 0; j < i; j++) {if (nums[i] > nums[j])dp[i] = Math.max(dp[i], dp[j] + 1);}}int res = 0;for (int i = 0; i < dp.length; i++) {res = Math.max(res, dp[i]);}return res;}
}

1143 最长公共子序列

给定两个字符串 text1 和 text2,返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 ,返回 0 。

  • dp[i][j]:长度为[0, i - 1]的字符串text1与长度为[0, j - 1]的字符串text2的最长公共子序列为dp[i][j]
  • 两种情况:text1[i - 1] 与 text2[j - 1]相同,text1[i - 1] 与 text2[j - 1]不相同
    • 如果text1[i - 1] 与 text2[j - 1]相同,那么找到了一个公共元素,所以 dp[i][j] = dp[i - 1][j - 1] + 1;
    • 如果text1[i - 1] 与 text2[j - 1]不相同,那就看看text1[0, i - 2]与text2[0, j - 1]的最长公共子序列 和 text1[0, i - 1]与text2[0, j - 2]的最长公共子序列,取最大的dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
    • dp 数组的第0行和第0列用于表示空字符串的情况
class Solution {public int longestCommonSubsequence(String text1, String text2) {  //dp 数组的第0行和第0列用于表示空字符串的情况int[][] dp = new int[text1.length() + 1][text2.length() + 1];for (int i = 1; i <= text1.length(); i++) {for (int j = 1; j <= text2.length(); j++) {char char1 = text1.charAt(i - 1);  //当 dp 数组的索引为 i 和 j 时,我们实际上是在处理 text1 的第 i-1 个字符和 text2 的第 j-1 个字符char char2 = text2.charAt(j - 1);if (char1 == char2) {dp[i][j] = dp[i - 1][j - 1] + 1;} else {dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);}}}return dp[text1.length()][text2.length()];}
}

72 编辑距离

给你两个单词 word1 和 word2, 请返回将 word1 转换成 word2 所使用的最少操作数

你可以对一个单词进行如下三种操作:

  • 插入一个字符
  • 删除一个字符
  • 替换一个字符

dp[i][j] 表示以下标i-1为结尾的字符串word1,和以下标j-1为结尾的字符串word2,最近编辑距离为dp[i][j]。

  1. if (word1[i - 1] == word2[j - 1]) 那么说明不用任何编辑,dp[i][j] 就应该是 dp[i - 1][j - 1],即dp[i][j] = dp[i - 1][j - 1];
  2. if (word1[i - 1] != word2[j - 1]),此时就需要编辑了,如何编辑呢?
  • 操作一:word1删除一个元素,那么就是以下标i - 2为结尾的word1 与 j-1为结尾的word2的最近编辑距离 再加上一个操作。

即 dp[i][j] = dp[i - 1][j] + 1;

  • 操作二:word2删除一个元素,那么就是以下标i - 1为结尾的word1 与 j-2为结尾的word2的最近编辑距离 再加上一个操作。

即 dp[i][j] = dp[i][j - 1] + 1;

  • 操作三:替换元素,word1替换word1[i - 1],使其与word2[j - 1]相同,此时不用增删加元素。

可以回顾一下,if (word1[i - 1] == word2[j - 1])的时候我们的操作 是 dp[i][j] = dp[i - 1][j - 1] 对吧。

那么只需要一次替换的操作,就可以让 word1[i - 1] 和 word2[j - 1] 相同。

所以 dp[i][j] = dp[i - 1][j - 1] + 1;

class Solution {public int minDistance(String s1, String s2) {int m = s1.length(), n = s2.length();int[][] dp = new int[m + 1][n + 1];// base case 有一个里面没元素for (int i = 1; i <= m; i++) //对word1里的元素全部做删除操作dp[i][0] = i;for (int j = 1; j <= n; j++)dp[0][j] = j;// 自底向上求解for (int i = 1; i <= m; i++)for (int j = 1; j <= n; j++)// 因为dp数组有效位从1开始// 所以当前遍历到的字符串的位置为i-1 | j-1if (s1.charAt(i - 1) == s2.charAt(j - 1))dp[i][j] = dp[i - 1][j - 1];elsedp[i][j] = min(dp[i - 1][j] + 1,//word1删除dp[i][j - 1] + 1,//word2删除dp[i - 1][j - 1] + 1//替换);// 储存着整个 s1 和 s2 的最小编辑距离return dp[m][n];}int min(int a, int b, int c) {return Math.min(a, Math.min(b, c));}
}

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

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

相关文章

【C++】 ubuntu下获取屏幕尺寸、分辨率

1. 给/dev/fb0权限 sudo chmod 0777 /dev/fb0 注意&#xff1a;不执行这一条权限&#xff0c;无法获取任何数据 2. 获取屏幕尺寸 int fd; struct fb_var_screeninfo screenInfo; fd open("/dev/fb0",O_RDWR); ioctl(fd,FBIOGET_VSCREENINFO,&screenInfo); pr…

【毛毛虫案例-拖拽 Objective-C语言】

一、这个毛毛虫案例啊,是这个样子的, 1.首先,你这个脑袋,这个蓝色的脑袋,它是可以拽起来的, 下面的红色球,一个一个中心点之间,相互去附着, 其他的红色球,是拖不起来的, 只有这个蓝色的东西,可以拽起来,这个蓝色的View,还有重力, 这个蓝色的View,我在拖动它…

[深度学习] 变分自编码器VAE

变分自编码器&#xff08;Variational Autoencoders, VAEs&#xff09;是一种生成模型 Tutorial on Variational Autoencoders&#xff0c;它结合了概率图模型和深度学习&#xff0c;通过学习数据的潜在表示来生成新的数据样本。VAEs在数据生成、异常检测、数据压缩等领域具有广…

如何应对UI测试自动化的不稳定循环!

以下为作者观点&#xff1a; 当我加入UI自动化团队时&#xff0c;我很高兴能为新功能的自动化测试用例开发做出贡献。然而&#xff0c;我很快意识到团队花费了大量时间来修复之前迭代中不稳定的测试。这种情况让我感到困惑&#xff0c;因为当自动化测试脚本已知不稳定时&#…

git使用中 error: pathspec ‘XXX‘ did not match any file(s) known to git 报错解决方法

报错原因 本人在本地开发中&#xff0c;切换线上新创建分支时&#xff1a; $ git checkout master01 error: pathspec master01 did not match any file(s) known to git解决方式 $ git branch -a | grep master * masterremotes/origin/HEAD -> origin/masterremotes/or…

python开发api接口框架

在现代软件开发领域中&#xff0c;API接口框架扮演着非常重要的角色。它可以帮助开发者快速搭建和部署API&#xff0c;提供数据交换的接口&#xff0c;使得不同系统之间可以进行通信和数据传输。Python作为一门功能强大且易于学习的编程语言&#xff0c;被广泛应用于API接口的开…

【Windows 常用工具系列 17 -- windows bat 脚本多参数处理】

请阅读【嵌入式开发学习必备专栏】 文章目录 bat 脚本命令行参数使用示例多参数处理使用示例遍历所有参数 bat 脚本命令行参数 在Windows批处理&#xff08;.bat&#xff09;脚本中接收命令行参数是一个常见的需求&#xff0c;这样的脚本能够根据提供的参数执行不同的操作。命…

Kubernetes之Controller详解

本文尝试从Kubernetes Controller的种类、交互逻辑、最佳实践、伪代码示例及历史演进5个方面对其进行详细阐述&#xff0c;希望对您有所帮助&#xff01; 一、Kubernetes Controller种类 Kubernetes Controller Manager 是 Kubernetes 集群的核心组件之一&#xff0c;负责管理…

身边的故事(十一 ):阿文的故事:红包

虽然是发小&#xff0c;但是小时候的记忆很模糊了&#xff0c;从哪里写起呢&#xff1f;时间节点从大学开始吧&#xff0c;初中的那些有机会后续再写了。 今年回家过年的时候收到阿番要结婚的消息。大年初三阿番就在微信上给我发电子请帖。阿番的女朋友和阿番同居已经有三四年。…

C++ std::array的原理和语法

原理 std::array 是C标准库提供的一个模板类&#xff0c;用于表示固定大小的数组。与传统的C风格数组不同&#xff0c;std::array 提供了更加安全和功能丰富的接口&#xff0c;并且它的大小在编译时就已经确定。std::array 实际上是对传统数组的一个轻量级封装&#xff0c;提供…

无线幅频仪制作(WiFi通信)-含STM32源程序,JAVA上位机与设计报告

资料下载地址&#xff1a;无线幅频仪制作(WiFi通信)-含STM32源程序,JAVA上位机与设计报告 目录 项目功能 1、 系统方案1.1 比较与选择 1.1.1 控制器的论证与选择 1.1.2 信号源的论证与选择 1.1.3 放大器模块的论证与选择 1.1.4 键盘与显示模块的论证与选择 1.1.5 网络通…

[保姆级教程]uniapp小程序获取右上角胶囊位置信息

文章目录 导文使用uni.getMenuButtonBoundingClientRect();方法实现完整案例 隐藏默认导航栏&#xff1a;全局隐藏当前页面隐藏 导文 uniapp小程序获取右上角胶囊位置信息 使用uni.getMenuButtonBoundingClientRect();方法实现 <script>const menuButtonInfo uni.getMe…

logstash配置文件中明文密码加密

1 案例背景 应用配置文件中禁止使用明文密码&#xff0c;需要加密处理 上图中&#xff0c;红框打码位置为es的明文密码&#xff0c;需要对其进行处理 2 创健keystore文件 /rpa/logstash/bin/logstash-keystore --path.settings /rpa/isa/conf/logstash/ create 注&#xff1…

记录正则提取文章

收到了个word版的电子书&#xff0c;需要拆分并转换为md存储到数据库中&#xff0c;便于搜索&#xff0c;记录下用正则提取文章的过程 word原文中有目录&#xff0c;可提取出目录后&#xff0c;在正文中根据目录来正则提取文章 正则的多行匹配 在匹配大量文章的时候&#xff…

互联网时代的语义网知识表示框架---OWL和OWL2 Fragments

文章目录 RDF和RDFSOWL的重要词汇RDF和RDFS 前面介绍了RDF和RDFS,通过RDF (S)可以表示一些简单的语义,但在更复杂的场景下, RDF (S)语义的表达能力显得太弱,还缺少常用的特征: 对于局部值域的属性定义。RDF (S)中通过rdfs:range定义了属性的值域,该值域是全局性的…

llm-universe | 四. 构建RAG应用

构建RAG应用 一.将LLM 接入 LangChain二.构建检索问答链1.加载向量数据库2.创建一个 LLM3.构建检索问答链4.检索问答链效果测试5.添加历史对话的记忆功能5.1 记忆&#xff08;Memory&#xff09;5.2 对话检索链&#xff08;ConversationalRetrievalChain&#xff09; 三. 部署知…

ts可选参数

可选参数 参数后加个问号&#xff0c;代表这个参数是可选的 function bdd(x:number,y?:number){return x y } console.log(bdd(2,3)) function bdd(x:number,y?:number){return x y } console.log(bdd(2))

从0到1构建自己的短链接系统

1. 短链系统简介 1.1 短链系统的定义与用途 短链系统是指将一个较长的URL地址&#xff0c;通过特定的算法生成一个较短的、具备唯一性的URL地址。这种系统广泛应用于社交网络、短信、邮件营销等场景&#xff0c;它能帮助用户在字数受限的情况下分享链接&#xff0c;并且还具有…

Jenkins 创建流水线任务

Jenkins是一个流行的持续集成&#xff08;Continuous Integration&#xff0c;CI&#xff09;工具。 Jenkins 创建任务 选择“流水线”类型&#xff0c;该类型的优点是定制化程度非常高 &#xff08;可选&#xff09;添加“参数化构建” 配置仓库选项(ssh连接、分支)和凭据…