一句话总结:动规做多了就豁然开朗了。
原题链接:300 最长递增子序列
按照动规五部曲:
- 首先确定dp数组及下标的含义:dp[i]表示以nums[i]结尾的最长子序列的长度;
- 确定状态转移方程:如果nums[i] > nums[j](其中j < i),那么dp[i] = Math.max(dp[i], dp[j] + 1),即位置i的最长升序子序列等于j从0到i-1各个位置的最长升序子序列 + 1 的最大值;
- dp数组的初始化:每个子序列最开始都是1,所以初始化为1;
- 数组的遍历顺序:可见dp[i]取决于每一个小于i的j的值,因此从前往后遍历;
- 举例推导dp数组:过程略。
最终代码如下:
class Solution {
public int lengthOfLIS(int[] nums) {
int n = nums.length;
int[] dp = new int[n];
Arrays.fill(dp, 1);
int ans = 1;
for (int i = 1; i < n; ++i) {
for (int j = 0; j < i; ++j) {
if (nums[j] < nums[i]) {
dp[i] = Math.max(dp[i], dp[j] + 1);
}
}
ans = Math.max(dp[i], ans);
}
return ans;
}
}
原题链接: 674 最长连续递增序列
找的是连续递增子序列,因此直接一次遍历即可解决,如果当前数大于前一个数,那么cnt+1,否则将cnt重置为1。最后取所有cnt值中最大的一位即可。
class Solution {
public int findLengthOfLCIS(int[] nums) {
int n = nums.length;
int ans = 1, cnt = 1;
for (int i = 1; i < n; ++i) {
if (nums[i] > nums[i - 1]) ++cnt;
else cnt = 1;
ans = Math.max(ans, cnt);
}
return ans;
}
}
这里用的是贪心思想,动规做法即上一题的改动,一趟遍历即可,过程差不多。
原题链接:718 最长重复子数组
最基础的做法是二维dp数组。按照动规五部曲,过程如下:
- 确定dp数组及下标的含义:dp[i][j]表示nums1数组的第i位与nums2数组的第j位的最长重复子数组的长度;
- 确定状态转移方程:dp[i][j]只能由dp[i - 1][j - 1]推导而来,即if (nums1[i - 1] == nums2[j - 1]) {dp[[i][j] = dp[i - 1][j - 1] + 1}。而如果两者不等,那么即为0;
- dp数组的初始化:为了递归方便,所有dp[i][0] 和所有dp[0][i]都初始化为0;
- 确定dp数组的遍历顺序:从前往后,两层循环分别对nums1数组和nums2数组遍历即可;
- 举例推导dp数组:过程略。
最终代码如下:
class Solution {
public int findLength(int[] nums1, int[] nums2) {
int m = nums1.length, n = nums2.length;
int[][] dp = new int[m + 1][n + 1];
for (int i = 0; i <= m; ++i) {
dp[i][0] = 0;
}
for (int i = 0; i <= n; ++i) {
dp[0][i] = 0;
}
int ans = 0;
for (int i = 1; i <= m; ++i) {
for (int j = 1; j <= n; ++j) {
if (nums1[i - 1] == nums2[j - 1]) {
dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - 1] + 1);
}
ans = Math.max(ans, dp[i][j]);
}
}
return ans;
}
}
另有滚动数组解法,利用一维dp数组即可。需要注意内层循环为了避免重复覆盖,因此采用从后往前遍历顺序。
class Solution {
public int findLength(int[] nums1, int[] nums2) {
int[] dp = new int[nums2.length + 1];
int ans = 0;
for (int i = 1; i <= nums1.length; i++){
for (int j = nums2.length; j >= 1; j--){
if (nums1[i - 1] == nums2[j - 1]){
dp[j] = dp[j - 1] + 1;
} else {
dp[j] = 0;
}
ans = Math.max(dp[j], ans);
}
}
return ans;
}
}