300.最长递增子序列
题目
给你一个整数数组 nums
,找到其中最长严格递增子序列的长度。
子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7]
是数组 [0,3,1,6,2,2,7]
的子序列。
示例 1:
输入:nums = [10,9,2,5,3,7,101,18] 输出:4 解释:最长递增子序列是 [2,3,7,101],因此长度为 4 。
示例 2:
输入:nums = [0,1,0,3,2,3] 输出:4
代码
class Solution {public int lengthOfLIS(int[] nums) {int n = nums.length; //元素个数//dp[i]:以i为子序列末尾元素的子序列最长值int[] dp = new int[n];//初始化:默认子序列都是1Arrays.fill(dp, 1);int max = 1; //保存dp[i]的最大值//遍历顺序:fori移动子序列的末尾元素for(int i=1; i < n; i++){//forj:求出以i为子序列末尾元素的子序列最长值for(int j=0; j < i; j++){//如果nums[i] > nums[j],说明i有可能成为j后面的子序列if(nums[i] > nums[j]){//dp[j]表示以j为子序列末尾元素的子序列最长值//+1说明i需要接入j后面的子序列了dp[i] = Math.max(dp[i], dp[j] + 1);}max = Math.max(max,dp[i]); //更新dp[i]最大值}}return max;}
}
674.最长连续递增子序列
题目
给定一个未经排序的整数数组,找到最长且 连续递增的子序列,并返回该序列的长度。
连续递增的子序列 可以由两个下标 l
和 r
(l < r
)确定,如果对于每个 l <= i < r
,都有 nums[i] < nums[i + 1]
,那么子序列 [nums[l], nums[l + 1], ..., nums[r - 1], nums[r]]
就是连续递增子序列。
示例 1:
输入:nums = [1,3,5,4,7] 输出:3 解释:最长连续递增序列是 [1,3,5], 长度为3。 尽管 [1,3,5,7] 也是升序的子序列, 但它不是连续的,因为 5 和 7 在原数组里被 4 隔开。
代码(贪心)
class Solution {public int findLengthOfLCIS(int[] nums) {//贪心int res = 1; //全局连续递增子序列长度int tmpLen = 1; //局部连续递增子序列长度for(int i=1; i < nums.length; i++){//连续递增,只用比较i和i-1的大小if(nums[i] > nums[i-1]){tmpLen++; //局部连续递增子序列长度}else{tmpLen = 1; //出现不递增的情况,tmp归1,重新寻找递增}res = Math.max(res, tmpLen);}return res;}
}
代码(动态规划)
class Solution {public int findLengthOfLCIS(int[] nums) {//动态规划//dp[i]表示以i为连续递增子序列末尾元素的序列最大值int[] dp = new int[nums.length];//初始化:默认全为1Arrays.fill(dp, 1);int res = 1; //保存dp[i]的最大值//遍历顺序:从前往后for(int i=1; i < nums.length; i++){//比较i和i-1的大小if(nums[i] > nums[i-1]){dp[i] = dp[i-1] + 1; //i满足递增条件}// else{// dp[i] = 1; //i不满足递增条件,子序列重新计算// }res = Math.max(res, dp[i]);}return res;}
}
718、最长重复子数组
题目
给两个整数数组 nums1
和 nums2
,返回 两个数组中 公共的 、长度最长的子数组的长度 。
示例 1:
输入:nums1 = [1,2,3,2,1], nums2 = [3,2,1,4,7] 输出:3 解释:长度最长的公共子数组是 [3,2,1] 。
代码
class Solution {public int findLength(int[] nums1, int[] nums2) {int len1 = nums1.length; //nums1元素个数int len2 = nums2.length; //nums2元素个数//dp[i][j]表示以i为nums1的末尾元素,以j为nums2的末尾元素的相同子数组最大长度int[][] dp = new int[len1][len2];int res = 0; //保存最大子数组的长度//初始化第一列for(int i=0; i < len1; i++){if(nums1[i] == nums2[0]){dp[i][0] = 1;res = 1; //更新最大子数组的长度}}//初始化第一行for(int j=0; j < len2; j++){if(nums2[j] == nums1[0]){dp[0][j] = 1;res = 1; //更新最大子数组的长度}}//遍历顺序(交换也行)for(int i=1; i < len1; i++){for(int j=1; j < len2; j++){if(nums1[i] == nums2[j]){ //i和j元素值相同//递推公式:i-1和j-1的数组子序列相同,加上i和j也相同,子序列长度+1dp[i][j] = dp[i-1][j-1] + 1;}res = Math.max(res, dp[i][j]); //更新最大子数组的长度}}return res;}
}
代码(优化初始化)
class Solution {public int findLength(int[] nums1, int[] nums2) {int len1 = nums1.length; //nums1元素个数int len2 = nums2.length; //nums2元素个数//dp[i][j]表示以nums1[i-1]的末尾元素,以nums2[j-1]的末尾元素的相同子数组最大长度int[][] dp = new int[len1+1][len2+1];int res = 0; //保存最大子数组的长度//dp数组初始化,dp[0][j]和dp[i][0]全为0//这种写法可以简化第一行第一列的初始化//遍历顺序(交换也行)for(int i=1; i <= len1; i++){for(int j=1; j <= len2; j++){if(nums1[i-1] == nums2[j-1]){ //i和j元素值相同//递推公式:i-2和j-1的数组子序列相同,加上i-1和j-1也相同,子序列长度+1dp[i][j] = dp[i-1][j-1] + 1;}res = Math.max(res, dp[i][j]); //更新最大子数组的长度}}return res;}
}
1143、最长公共子序列
题目
给定两个字符串 text1
和 text2
,返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 ,返回 0
。
一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。
- 例如,
"ace"
是"abcde"
的子序列,但"aec"
不是"abcde"
的子序列。
两个字符串的 公共子序列 是这两个字符串所共同拥有的子序列。
示例 1:
输入:text1 = "abcde", text2 = "ace" 输出:3 解释:最长公共子序列是 "ace" ,它的长度为 3 。
代码(优化初始化)
class Solution {public int longestCommonSubsequence(String text1, String text2) {int len1 = text1.length(); //text1长度int len2 = text2.length(); //text2长度//dp[i][j]表示[0,i-1]的text1与[0,j-1]的text2的最长公共子序列int[][] dp = new int[len1+1][len2+1];//初始化:默认dp[0][j],dp[i][0]全为0//把dp多扩展一个行列,就不用处理text1[0]和text2[0]的初始化情况了//变相的把初始化的计算和下面的递推合在一起//遍历顺序for(int i=1; i <= len1; i++){for(int j=1; j <= len2; j++){//递推公式,text1[i-1]和text2[j-1]相同if(text1.charAt(i-1) == text2.charAt(j-1)){dp[i][j] = dp[i-1][j-1] + 1; //在i-2和j-2的基础上长度+1}//text1[i-1]和text2[j-1]不相同else{//ab,ac取(ab,a)和(a,ac)两者的最大长度dp[i][j] = Math.max(dp[i-1][j], dp[i][j-1]);}}}return dp[len1][len2]; //返回最长公共子序列}
}