引言
阅读完本篇文章,你可以在力扣顺便解决以下题目:
300. 最长递增子序列 | 1143. 最长公共子序列 | 1035. 不相交的线 |
---|---|---|
674. 最长连续递增序列 | 718. 最长重复子数组 | 53. 最大子序和 |
392. 判断子序列 | 115. 不同的子序列 | 583. 两个字符串的删除操作 |
72. 编辑距离 | 647. 回文子串 | 516. 最长回文子序列 |
原图链接:https://www.processon.com/view/link/67209a676b5a4a4adda5922c?cid=66c30d46fb35b76d02e00e5b
300. 最长递增子序列(中等)
☘️代码实现
class Solution {
public int lengthOfLIS(int[] nums) {
if(nums.length <= 1) return nums.length;
int n = nums.length;
int res = 0;
// dp[i]表示以nums[i]结尾的最长递增子序列的长度
int[] dp = new int[n];
for(int i = 0;i<n;i++){
dp[i] = 1;
}
for(int i = 1;i<n;i++){
for(int j = 0;j<i;j++){
if(nums[i] > nums[j]){
dp[i] = Math.max(dp[i],dp[j]+1);
}
res = Math.max(res,dp[i]);
}
}
return res;
}
}
1143. 最长公共子序列(中等)
☘️代码实现
class Solution {
public int longestCommonSubsequence(String text1, String text2) {
// dp[i][j]表示长度为i-1的字符串text1与长度j-1的字符串text2的最长公共子序列
int[][] dp = new int[text1.length()+1][text2.length()+1];
int res = 0;
for(int i=1;i<=text1.length();i++){
for(int j=1;j<=text2.length();j++){
if(text1.charAt(i-1) == text2.charAt(j-1)){
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()];
}
}
1035. 不相交的线(中等)
☘️代码实现
class Solution {
public int maxUncrossedLines(int[] nums1, int[] nums2) {
// 跟 1143 题如出一辙
// dp[i][j]表示长度为i-1的数组nums1与长度j-1的数组nums2的最大连线数
int[][] dp = new int[nums1.length+1][nums2.length+1];
int res = 0;
for(int i=1;i<=nums1.length;i++){
for(int j=1;j<=nums2.length;j++){
if(nums1[i-1] == nums2[j-1]){
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[nums1.length][nums2.length];
}
}
674. 最长连续递增序列(中等)
☘️代码实现
class Solution {
public int findLengthOfLCIS(int[] nums) {
if(nums.length == 0) return 0;
int n = nums.length;
int res = 1;
// dp[i]:以下标i为结尾的连续递增的子序列长度为dp[i]。
int[] dp = new int[n];
// 初始化
Arrays.fill(dp,1);
for(int i = 1;i<n;i++){
if(nums[i] > nums[i-1]){
dp[i] = dp[i-1] + 1;
}
res = Math.max(res,dp[i]);
}
return res;
}
}
718. 最长重复子数组(中等)
☘️代码实现
class Solution {
public int findLength(int[] nums1, int[] nums2) {
int m = nums1.length;
int n = nums2.length;
int res = 0;
// dp[i][j] :以下标i - 1为结尾的A,和以下标j - 1为结尾的B,最长重复子数组长度为dp[i][j]
int[][] dp = new int[m+1][n+1];
for(int i = 1;i<=m;i++){
for(int j = 1;j<=n;j++){
if(nums1[i-1] == nums2[j-1]){
dp[i][j] = dp[i-1][j-1] + 1;
}
res = Math.max(res,dp[i][j]);
}
}
return res;
}
}
53. 最大子序和(中等)
☘️代码实现
class Solution {
public int maxSubArray(int[] nums) {
int n = nums.length;
int res = nums[0];
// dp[i]:包括下标i(以nums[i]为结尾)的最大连续子数组和为dp[i]。
int[] dp = new int[n];
dp[0] = nums[0];
for(int i = 1;i<n;i++){
// 这里有点东西啊。。。
dp[i] = Math.max(nums[i],dp[i-1] + nums[i]);
res = Math.max(res,dp[i]);
}
return res;
}
}
392. 判断子序列(简单)
☘️代码实现
class Solution {
public boolean isSubsequence(String s, String t) {
if(s.length() > t.length()) return false;
// dp[i][j] 表示以下标i-1为结尾的字符串s,和以下标j-1为结尾的字符串t,相同子序列的长度为dp[i][j]
int[][] dp = new int[s.length()+1][t.length()+1];
for(int i=1;i<=s.length();i++){
for(int j=1;j<=t.length();j++){
if(s.charAt(i-1) == t.charAt(j-1)) {
dp[i][j] = dp[i-1][j-1] + 1;
}else {
dp[i][j] = dp[i][j-1];
}
}
}
return dp[s.length()][t.length()] == s.length();
}
}
115. 不同的子序列(困难)
☘️代码实现
class Solution {
public int numDistinct(String s, String t) {
int s1 = s.length();
int t1 = t.length();
// 其实就稍微麻烦了一点,细心一点也很简单
// dp[i][j]:以i-1为结尾的s子序列中出现以j-1为结尾的t的个数为dp[i][j]。
int[][] dp = new int[s1+1][t1+1];
// dp[i][0] 表示:以i-1为结尾的s可以随便删除元素,出现空字符串的个数。
// 那么dp[i][0]一定都是1,因为也就是把以i-1为结尾的s,删除所有元素,出现空字符串的个数就是1。
for(int i=0;i<s1;i++) dp[i][0] = 1;
for(int i=1;i<=s1;i++){
for(int j=1;j<=t1;j++){
if(s.charAt(i-1) == t.charAt(j-1)){
dp[i][j] = dp[i-1][j-1] + dp[i-1][j];
}else {
dp[i][j] = dp[i-1][j];
}
}
}
return dp[s1][t1];
}
}
583. 两个字符串的删除操作
☘️代码实现
class Solution {
public int minDistance(String word1, String word2) {
int s1 = word1.length();
int s2 = word2.length();
// dp[i][j]:以i-1为结尾的字符串word1,和以j-1位结尾的字符串word2,想要达到相等,所需要删除元素的最少次数
int[][] dp = new int[s1+1][s2+1];
for(int i = 0;i<=s1;i++){
dp[i][0] = i;
}
for(int j = 0;j<=s2;j++){
dp[0][j] = j;
}
for(int i = 1;i<=s1;i++){
for(int j = 1;j<=s2;j++){
if(word1.charAt(i-1) == word2.charAt(j-1)){
dp[i][j] = dp[i-1][j-1];
}else {
dp[i][j] = Math.min(dp[i-1][j] + 1,dp[i][j-1] + 1);
}
}
}
return dp[s1][s2];
}
}
72. 编辑距离
☘️代码实现
class Solution {
public int minDistance(String word1, String word2) {
// dp[i][j] 表示以下标i-1为结尾的字符串word1,和以下标j-1为结尾的字符串word2,最近编辑距离为dp[i][j]
int[][] dp = new int[word1.length()+1][word2.length()+1];
for(int i=0;i<=word1.length();i++) dp[i][0] = i;
for(int j=1;j<=word2.length();j++) dp[0][j] = j;
for(int i = 1;i<=word1.length();i++){
for(int j = 1;j<=word2.length();j++){
if(word1.charAt(i-1) == word2.charAt(j-1)){
dp[i][j] = dp[i-1][j-1];
}else {
// 只需要一次替换的操作,就可以让 word1[i - 1] 和 word2[j - 1] 相同
// 所以 dp[i][j] = dp[i - 1][j - 1] + 1
dp[i][j] = Math.min(dp[i-1][j-1],Math.min(dp[i-1][j],dp[i][j-1])) + 1;
}
}
}
return dp[word1.length()][word2.length()];
}
}
647. 回文子串
☘️代码实现
class Solution {
public int countSubstrings(String s) {
// dp[i][j]:表示区间范围[i,j]的子串是否是回文子串,如果是dp[i][j]为true,否则为false
boolean[][] dp = new boolean[s.length()][s.length()];
int res = 0;
// 从下往上,从左到右遍历dp[i+1][j-1] -> dp[i][j]
for(int i=s.length()-1;i>=0;i--){
for(int j=i;j<s.length();j++){
if(s.charAt(i) == s.charAt(j)){
// 情况一:下标i 与 j相同,同一个字符例如a,当然是回文子串
// 情况二:下标i 与 j相差为1,例如aa,也是回文子串
if(j-i <= 1){
res++;
dp[i][j] = true;
// 情况三:下标:i 与 j相差大于1的时候,例如cabac,此时s[i]与s[j]已经相同了,我们看
// i到j区间是不是回文子串就看aba是不是回文就可以了,那么aba的区间就是 i+1 与 j-1区间,
// 这个区间是不是回文就看dp[i + 1][j - 1]是否为true
} else if(dp[i+1][j-1]){
res++;
dp[i][j] = true;
}
}
}
}
return res;
}
}
516. 最长回文子序列
☘️代码实现
class Solution {
public int longestPalindromeSubseq(String s) {
// dp[i][j]:表示字符串s在[i,j]范围内最长的回文子序列的长度
int[][] dp = new int[s.length()][s.length()];
for(int i = 0;i<s.length();i++){
dp[i][i] = 1;
}
for(int i = s.length()-1;i>=0;i--){
for(int j = i+1;j<s.length();j++){
if(s.charAt(i) == s.charAt(j)){
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][s.length()-1];
}
}