力扣动态规划基础版(字符串应用)

embedded/2024/11/28 12:07:54/

5.最长回文串

5. 最长回文子串icon-default.png?t=O83Ahttps://leetcode.cn/problems/longest-palindromic-substring/

先全部置为false然后反向遍历。动态规划数组,dp【i】【j】表示从第i到第j 是否是回文串。Arrays.fill表示的是将指定的内容填充到数组中。状态转移方程如下

这个题目用到了charAt索引处,所以就不必要去索引对齐,因为你索引对齐了以后,使用charAt的时候还是要+-1还是很麻烦

charAt:从字符串中取第几个数

Arrays.fill:批量填充

substring:取子集

class Solution {public String longestPalindrome(String s) {int m = s.length();boolean[][] dp = new boolean[m][m];int res = 0;String str = "";for(int i = 0; i < m; ++i){Arrays.fill(dp[i],false);} for(int i = m - 1 ; i >= 0; i--){for(int j = i; j < m; ++j){if(s.charAt(i) == s.charAt(j) &&(j - i <= 1 || dp[i + 1][j - 1])){dp[i][j] = true;res = Math.max(res,j - i + 1);if(j - i + 1>= res){str = s.substring(i, j +1);}}}}return str;}
}

139.单词拆分 

139. 单词拆分icon-default.png?t=O83Ahttps://leetcode.cn/problems/word-break/这里的状态转移方程就是下式,check检查是否出现。首先创建了一个哈希表取排除了这个相同的元素,HashSet不保证元素的顺序,并且不允许null元素。

其次需要注意是,创建哈希表时范围+1来保证索引对齐 ,dp【i】表示的就是第i个数字之前能由拆分的单词组成。边界条件是dp【0】 =true表示空串并且合法,这里要注意substring函数的使用表示的是取从第i个字符到第j  - 1 个字符子串。

contains方法:个集合或数组中是否包含特定的元素

class Solution {public boolean wordBreak(String s, List<String> wordDict) {Set<String> wordDictSet = new HashSet(wordDict);boolean []dp = new boolean[s.length() + 1];//为了索引对齐(下一行)dp[0] = true;for(int i = 1; i <= s.length(); ++i){for(int j = 0; j < i; ++j){if(dp[j] && wordDictSet.contains(s.substring(j ,i))){dp[i] = true;break;}}}return dp[s.length()];}
}

516.最长回文子序列

516. 最长回文子序列icon-default.png?t=O83Ahttps://leetcode.cn/problems/longest-palindromic-subsequence/

用 dp[i][j] 表示字符串 s 的下标范围 [i,j] 内的最长回文子序列的长度。假设字符串 s 的长度为 n,则只有当 0≤i≤j<n 时,才会有 dp[i][j]>0,否则 dp[i][j]=0。

边界:由于任何长度为 1 的子序列都是回文子序列,因此动态规划的边界情况是,对任意 0≤i<n,都有 dp[i][i]=1。

(1) s[i]=s[j]         dp[i][j]=dp[i+1][j−1]+2;

(2) s[i]!=s[j]        dp[i][j]=max(dp[i+1][j],dp[i][j−1])。

class Solution {public int longestPalindromeSubseq(String s) {int n = s.length();int dp[][] = new int [n][n];for(int i = n - 1; i >= 0; --i){dp[i][i] = 1;char c1 = s.charAt(i);for(int j = i + 1; j < n; ++j){char c2 = s.charAt(j);if(c1 == c2){dp[i][j] = dp[i + 1][j - 1] + 2;}else{dp[i][j] =  Math.max(dp[i + 1][j],dp[i][j -1]);}}}return dp[0][n -1];}
}

712.两个字符串的最小ASCII删除和 

712. 两个字符串的最小ASCII删除和icon-default.png?t=O83Ahttps://leetcode.cn/problems/minimum-ascii-delete-sum-for-two-strings/  dp[i][j] 表示使 s1​[0:i] 和 s2​[0:j] 相同的最小 ASCII 删除和

i = j = 0时,都为空不需要删除,dp[0][0] = 0,当i=0,j>0或i>0,j=0的时候,如果要相同,就需要删除全部的字符

这里codePointAt函数是取ASCII

当 i>0 且 j>0 时,考虑 dp[i][j] 的计算,

要得到使 s 1[0:i] 和 s 2[0:j] 相同的最小 ASCII 删除和,应取两项中较小的一项

class Solution {public int minimumDeleteSum(String s1, String s2) {int m = s1.length();int n = s2.length();int dp[][] = new int [m + 1][n + 1];for(int i = 1; i <= m; ++i){dp[i][0]  = dp[i - 1][0] + s1.codePointAt(i - 1);//只考虑s1的前i -1个字符删除s1中的字符和s2匹配}for(int j = 1; j <= n; ++j){dp[0][j] = dp[0][j - 1] + s2.codePointAt(j - 1);}for(int i = 1; i <= m; ++i){int c1 = s1.codePointAt(i - 1);for(int j = 1; j <= n; ++j){int c2 = s2.codePointAt(j - 1);if(c1 == c2){dp[i][j] = dp[i - 1][j - 1];}else{dp[i][j] = Math.min(dp[i - 1][j] + c1,dp[i][j - 1] + c2);}}}return dp[m][n];}
}

115.不同的子序列 

115. 不同的子序列icon-default.png?t=O83Ahttps://leetcode.cn/problems/distinct-subsequences/dp的 hard题目,稍微难想,套路相似,定义dp的含义是s和t两个字符串dp[i][j]表示的是t字符串从索引为j到最后末尾这个字串是否是s字符串索引为i的字串的子集。

考虑动态规划的边界情况,就是j = n的时候,t字符串是空集,空集是任何字符串的子集,所以对于任意0≤i≤m,有 dp[i][n]=1;

当 i=m 且 j<n 时,s[i:] 为空字符串,t[j:] 为非空字符串,由于非空字符串不是空字符串的子序列,因此对任意 0≤j<n,有 dp[m][j]=0。

当 i<m 且 j<n 时,考虑 dp[i][j] 的计算:

当 s[i]=t[j] 时,dp[i][j] 由两部分组成:

这里涉及一个匹配和不匹配的问题,就是说,当s[i]=t[j] ,s[i]可以去匹配t[j]的这个字符也可以不匹配,当不相等的时候就一定不匹配

class Solution {public int numDistinct(String s, String t) {int m = s.length();int n = t.length();if(m < n){return 0;}int [][] dp = new int[m + 1][n + 1];for(int i = 1; i <= m; ++i){dp[i][n] = 1;}for(int i = m - 1; i >= 0; i--){char c1 = s.charAt(i);for(int j = n - 1; j >= 0;j--){char c2 = t.charAt(j);if(c1 == c2){dp[i][j] = dp[i + 1][j + 1] + dp[i + 1][j];}else{dp[i][j] = dp[i + 1][j];}}}return dp[0][0];}
}


http://www.ppmy.cn/embedded/141175.html

相关文章

UE5 Add Transient Field 节点

在 Unreal Engine 5 (UE5) 中&#xff0c;Add Transient Field 是一个在 Niagara&#xff08;UE5 的粒子系统和 VFX 工具&#xff09;中使用的节点。这个节点的功能是动态地将一个 Transient Field&#xff08;瞬时字段&#xff09;添加到系统中&#xff0c;并将其应用到粒子系…

使用R语言绘制简单地图的教程

今天主要讲的部分是绘制静态地图&#xff0c;使用的R语言绘图包是tmap&#xff0c;关于介绍就不多讲&#xff0c;下面开始代码的讲解&#xff0c;小白也可以放心食用。 1、绘制简单的单幅地图&#xff0c;这里以新西兰地区为例 #导入必要的包 library(tmap) library(sp) libr…

【Linux】gcc/g++使用

编译 我们知道&#xff0c;gcc只能编译C&#xff0c;g既能编译C&#xff0c;也能编译C。 由于两者的选项是相同的&#xff0c;这里我们使用gcc来说明。 这就是一个我们在linux中gcc编译一段代码后会自动生成一个a.out为名的可执行文件&#xff0c;然后我们./a.out&#xff0c…

centos挂载ntfs或exFAT格式硬盘

记录一下centos系统中重挂载ntfs格式硬盘或exFAT格式硬盘。 首先使用命令 fdisk -l [rootlocalhost test]# fdisk -l ... ... ... ... WARNING: fdisk GPT support is currently new, and therefore in an experimental phase. Use at your own discretion.磁盘 /dev/sde&…

DataWhale—PumpkinBook(TASK05决策树)

课程开源地址及相关视频链接&#xff1a;&#xff08;当然这里也希望大家支持一下正版西瓜书和南瓜书图书&#xff0c;支持文睿、秦州等等致力于开源生态建设的大佬✿✿ヽ(▽)ノ✿&#xff09; Datawhale-学用 AI,从此开始 【吃瓜教程】《机器学习公式详解》&#xff08;南瓜…

Zabbix 7.0 LTS Docker Compose 部署指南与遇到问题解决

Zabbix 7.0 LTS Docker Compose 部署指南与遇到问题解决 摘要 本文详细介绍了如何使用Docker Compose部署Zabbix 7.0 LTS版本,并提供了针对常见部署问题的解决方案。主要内容包括: 完整的docker-compose.yml配置文件,包含Zabbix服务器、Web界面、Agent、Java Gateway和MyS…

php反序列化1_常见php序列化的CTF考题

声明&#xff1a; 以下多内容来自暗月师傅我是通过他的教程来学习记录的&#xff0c;如有侵权联系删除。 一道反序列化的CTF题分享_ctf反序列化题目_Mr.95的博客-CSDN博客 一些其他大佬的wp参考&#xff1a;php_反序列化_1 | dayu’s blog (killdayu.com) 序列化一个对象将…

Dockerfile打包部署

Dockerfile打包 先找到打包完的目录下创建一个Dockerfile文件 touch Dockerfile 进去文件内编写 vim Dockerfile # 基础镜像 FROM openjdk:8 # author MAINTAINER yxh # 挂载目录 VOLUME /home/project # 创建目录 RUN mkdir -p /home/project # 指定路径 WORKDIR /home/pr…