1143.最长公共子序列
给定两个字符串 text1 和 text2,返回这两个字符串的最长公共子序列的长度。
一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。
例如,"ace" 是 "abcde" 的子序列,但 "aec" 不是 "abcde" 的子序列。两个字符串的「公共子序列」是这两个字符串所共同拥有的子序列。
若这两个字符串没有公共子序列,则返回 0。
示例 1:
输入:text1 = "abcde", text2 = "ace" 输出:3 解释:最长公共子序列是 "ace",它的长度为 3。
解题思路
确定dp数组下标及含义
dp[i][j]:表示test1[0,i-1]与test2[0,j-1]的最长公共子序列为dp[i][j]. 之所以是i-1、j-1是为了方便初始化。
确定递推公式
情况一:test1[i-1] == test2[j-1]
dp[i][j]是由dp[i-1][j-1] +1 得来的,所以:dp[i][j] = dp[i-1][j-1] + 1;
情况二:test1[i-1]!=test2[j-1]
那么dp[i][j] 可取dp[i-1][j] 或者 dp[i][j-1] 中的最大值
所以dp[i][j] =max( dp[i-1][j],dp[i][j-1]);
3.dp数组初始化
dp[i][0] = 0;
dp[0][j] = 0;
代码示例-java
class Solution {
public int longestCommonSubsequence(String text1, String text2) {
// 定义dp数组
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++){
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.不相交的线
我们在两条独立的水平线上按给定的顺序写下 A 和 B 中的整数。
现在,我们可以绘制一些连接两个数字 A[i] 和 B[j] 的直线,只要 A[i] == B[j],且我们绘制的直线不与任何其他连线(非水平线)相交。
以这种方法绘制线条,并返回我们可以绘制的最大连线数。
解题思路
要找出A、B中相同的元素连线,并且要求连续不能相交的最大条数,那么可以看做求A、B中的最长公共子序列。那么其实现与上题1143.最长公共子序列 几乎一样。
代码示例-java
class Solution {
public int maxUncrossedLines(int[] nums1, int[] nums2) {
// 定义dp数组
int[][] dp = new int[nums1.length+1][nums2.length+1];
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];
}
}
53. 最大子序和
给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
示例: 输入: [-2,1,-3,4,-1,2,1,-5,4] 输出: 6 解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
解题思路
动态规划法:
确定dp数组下标及含义
dp[i] : 以nums[i] 为结尾的子数组最大和为 dp[i]
确定递推公式
一、dp[i] 可由dp[i-1]+nums[i]得来,即:dp[i] = dp[i-1] + nums[i]
二、dp[i] 是子数组的第一个元素,即: dp[i] = nums[i]
初始化
根据递推公式需要:dp[0] = nums[0]
遍历顺序
i从小到大
贪心法:
定义两个全局变量,分别记录当前区间和count(初始为0),和最大区间和sum(初始为最小整数)
从前向后遍历,不断累加元素到count上,并且比较count和sum ,将最大值赋给sum.
然后对于count一旦小于零,就重置为0,相当于重置了区间开头。最终得到的sum就是最大的。
代码示例-java
动态规划
class Solution {
public int maxSubArray(int[] nums) {
// 定义dp数组
int[] dp = new int[nums.length];
// 初始化
dp[0] = nums[0];
// 遍历
int res = dp[0];
for(int i=1;i<nums.length;i++){
dp[i] = Math.max(dp[i-1] + nums[i] ,nums[i]) ;
res = Math.max(dp[i],res);
}
return res;
}
}
贪心算法
class Solution {
public int maxSubArray(int[] nums) {
if(nums.length==1){
return nums[0];
}
int count = 0;
int sum = Integer.MIN_VALUE;
for(int i=0;i<nums.length;i++){
count+=nums[i];
// 取区间累计的最大值,重置区间结束位置
sum = Math.max(sum,count);
// 当区间和小于等于0时,重置count。相当于重置区间起始位置
if(count<=0){
count = 0;
}
}
return sum;
}
}