代码随想录算法训练营第五十三天|1143.最长公共子序列、1035.不相交的线、53.最大子序和
1143.最长公共子序列
给定两个字符串 text1
和 text2
,返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 ,返回 0
。
一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。
- 例如,
"ace"
是"abcde"
的子序列,但"aec"
不是"abcde"
的子序列。
两个字符串的 公共子序列 是这两个字符串所共同拥有的子序列。
示例 1:
输入:text1 = "abcde", text2 = "ace"
输出:3
解释:最长公共子序列是 "ace" ,它的长度为 3 。
题解:在上一题的基础上多考虑一个条件,那就是当前两个数组元素还要分开考虑一下。
-
dp(i,j) :表示数组1 到以 i-1 为结尾 和 数组2 以 j-1 为结尾的最长公共子序列
-
递推公式 :如果两个元素相等,那就是最长重复子数组的情况 dp(i,j)=max(dp(i-1,j-1)+1,dp(i,j))
如果当前它们不相等,那要考虑1的前一位和2的当前位,以及2的前一位和1的当前位是否相等。 dp(i,j)=max(dp(i-1,j),dp(i,j-1))
-
初始化:把边界初始化为0
-
遍历顺序:从小到大
-
打印dp数组
代码:
class Solution {
public int longestCommonSubsequence(String text1, String text2) {
//模糊掉边界的处理
int len1=text1.length()+1;
int len2=text2.length()+1;
int [][] dp=new int[len1][len2];
int res=0;
for(int i=1;i<len1;i++){
for(int j=1;j<len2;j++){
if(text1.charAt(i-1)==text2.charAt(j-1))
dp[i][j]=Math.max(dp[i][j],dp[i-1][j-1]+1);
else
dp[i][j]=Math.max(dp[i-1][j],dp[i][j-1]);
res=Math.max(res,dp[i][j]);
}
}
return res;
}
}
1035.不相交的线
在两条独立的水平线上按给定的顺序写下 nums1
和 nums2
中的整数。
现在,可以绘制一些连接两个数字 nums1[i]
和 nums2[j]
的直线,这些直线需要同时满足:
nums1[i] == nums2[j]
- 且绘制的直线不与任何其他连线(非水平线)相交。
请注意,连线即使在端点也不能相交:每个数字只能属于一条连线。
以这种方法绘制线条,并返回可以绘制的最大连线数。
示例 1:
输入:nums1 = [1,4,2], nums2 = [1,2,4]
输出:2
解释:可以画出两条不交叉的线,如上图所示。
但无法画出第三条不相交的直线,因为从 nums1[1]=4 到 nums2[2]=4 的直线将与从 nums1[2]=2 到 nums2[1]=2 的直线相交。
题解:这个题和上一个题是一样的,只是描述不一样。
代码:
class Solution {
public int maxUncrossedLines(int[] nums1, int[] nums2) {
int len1=nums1.length+1;
int len2=nums2.length+1;
int res=0;
int [][] dp=new int[len1][len2];
for(int i=1;i<len1;i++){
for(int j=1;j<len2;j++){
if(nums1[i-1]==nums2[j-1])
dp[i][j]=Math.max(dp[i][j],dp[i-1][j-1]+1);
else
dp[i][j]=Math.max(dp[i-1][j],dp[i][j-1]);
res=Math.max(res,dp[i][j]);
}
}
return res;
}
}
53.最大子序和
给你一个整数数组 nums
,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
子数组
是数组中的一个连续部分。
示例 1:
输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。
题解:这个题贪心写过,贪心的思想是只要相加的和是正数,那么就加上这个值,不是的话就sum=0,重新开始即可。
dp思想:
- dp[i]: 以 i 为结尾的连续子序列的最大和
- 递推公式: dp[i]=max(dp[i-1]+nums[i],nums[i]);
- 初始化: dp[0]=nums[0];
- 遍历顺序:从小到大
- 打印dp数组
代码:
class Solution {
public int maxSubArray(int[] nums) {
int len=nums.length;
int [] dp=new int [len];
int res=nums[0];
dp[0]=nums[0];
for(int i=1;i<len;i++){
dp[i]=Math.max(dp[i-1]+nums[i],nums[i]);
res=Math.max(res,dp[i]);
}
return res;
}
}
贪心算法:
class Solution {
public int maxSubArray(int[] nums) {
int len=nums.length;
int res=Integer.MIN_VALUE;
int sum=0;
for(int i=0;i<len;i++){
sum+=nums[i];
if(sum>res) res=sum;
if(sum<0) sum=0;
}
return res;
}
}