1. 代码随想录-动规41.LC300最长递增子序列
题目链接
含义:dp[i]表示i之前包括i的以nums[i]结尾的最长递增子序列的长度
公式:位置i的最长升序子序列等于j从0到i-1各个位置的最长升序子序列 + 1 的最大值。if (nums[i] > nums[j]) dp[i] = max(dp[i], dp[j] + 1);
初始化:所有dp[i]都为1
最后结果不是dp[dp.length-1],而是所有dp[i]的最大值
代码
class Solution {
public int lengthOfLIS(int[] nums) {
int[] dp = new int[nums.length];
int max = 1;
for (int i=0; i<nums.length; i++){
dp[i] = 1;
}
for (int i=1; i<nums.length; i++){
for (int j=0; j<i; j++){
if (nums[i] > nums[j]){
dp[i] = Math.max(dp[i], dp[j]+1);
if (dp[i] > max){
max = dp[i];
}
}
}
}
return max;
}
}
2. 代码随想录-动规42.LC674. 最长连续递增序列
两个思路:
- 动规 dp[i]表示到nums[i]的最长连续递增序列,不用dp[j]了,if (nums[i] > nums[1]),则dp[i] = dp[i-1]+1。初始化dp[i]都等于1。
- curLength,maxLength。一旦小于或等于上一个,说明递增序列已结束。从当前重新开始一个新的递增序列。
代码
2版本
class Solution {
public int findLengthOfLCIS(int[] nums) {
int maxLength = 1;
int curLength = 1;
if (nums.length == 1){
return maxLength;
}
for (int i=1; i<nums.length; i++){
if (nums[i] > nums[i-1]){
curLength++;
if (curLength > maxLength){
maxLength = curLength;
}
}else{
curLength = 1;
}
}
return maxLength;
}
}
3. 代码随想录-动规43.LC718. 最长重复子数组
题目链接
讲解视频
i从0开始遍历,j从0开始遍历,当nums[i]和nums[j]相等时,就去看,前一个数字是否也相等,如果也相等,说明是连续子数组,则在i-1,y-1的基础上+1;如果前一个数字不相等,则做个标记,等于1。i=0和j=0的没有前一个可看,所以遍历从i=1和j=1开始。
用dp[i][j]来记录。最大的dp[i][j]即为最终值。
class Solution {
public int findLength(int[] nums1, int[] nums2) {
int[][] dp = new int[nums1.length][nums2.length];
int maxLength = 0;
for (int i=0; i<nums1.length; i++){
if (nums1[i] == nums2[0]){
dp[i][0] = 1;
maxLength = 1;
}
}
for (int j=0; j<nums2.length; j++){
if (nums2[j] == nums1[0]){
dp[0][j] = 1;
maxLength = 1;
}
}
for (int i=1; i<nums1.length; i++){
for (int j=1; j<nums2.length; j++){
if (nums1[i] == nums2[j]){
if (dp[i-1][j-1] != 0){
dp[i][j] = dp[i-1][j-1] + 1;
}else{
dp[i][j] = 1;
}
}
if (dp[i][j] > maxLength){
maxLength = dp[i][j];
}
}
}
return maxLength;
}
}
4. 代码随想录-动规44.LC1143. 最长公共子序列
题目链接
与上题相比,这题不连续了。还是上题的图和思路。递推公式需要改变。
dp[i][j]表示A串到索引i,B串到索引j时,的最长公共子序列长度。
所以dp[i][j]有两种情况:
1.if (text1.charAt(i) == text2.charAt(j)),则dp[i][j]=dp[i-1][j-1].
2.if (text1.charAt(i) != text2.charAt(j)),则看dp[i-1][j]和dp[i][j-1]的max
初始化:j=0时,从text1.indexOf(text2.charAt(0))开始,dp[i][0]=1;i=0同理。
charAt函数,如果找不到,返回-1
代码
class Solution {
public int longestCommonSubsequence(String text1, String text2) {
int[][] dp = new int[text1.length()][text2.length()];
int index1 = text1.indexOf(text2.charAt(0));
int index2 = text2.indexOf(text1.charAt(0));
if (index1 != -1){
for (int i=index1; i<text1.length(); i++){
dp[i][0] = 1;
}
}
if (index2 != -1){
for (int j=index2; j<text2.length(); j++){
dp[0][j] = 1;
}
}
for (int i=1; i<text1.length(); i++){
for (int j=1; j<text2.length(); j++){
if (text1.charAt(i) == text2.charAt(j)){
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()-1][text2.length()-1];
}
}
5. 代码随想录-动规50.LC72. 编辑距离
题目链接
dp[i][j]含义:word1在i索引并且word2在j索引时的编辑最短距离。
推导公式:分两种情况
word1.charAt(i) == word2.charAt(j): dp[i][j] = dp[i-1][j-1]
word1.charAt(i) != word2.charAt(j): 可增,可删,可替换,因此又分三种情况
- 【增】word1的索引i处增加一个与word2索引j相同的字符:dp[i-1][j] +1
- 【删(=增)】word1的索引i处减少字符(又等于word2增加字符):dp[j-1][i]+1
- 【替换】dp[i-1][j-1]+1
初始化:
先初始化dp[0][0],然后初始化i=0和j=0的边
以j=0的边为例,也分两种情况:
word.charAt(i) == word2.charAt(0):dp[i][0] = dp[i-1][0] i(注意!dp[i-1][0]没考虑到:如果dp[0][0]已经等于0了已经相同了,i这里又出现一个相同的,也必须操作一次删掉,而不是=dp[i-1][0]不操作。所以dp[i][0] 应该等于 i)
word.charAt(i) != word2.charAt(0):dp[i][0] = dp[i-1][0]+1
最后,这道题的边界条件要考虑。因为题目中说word1和word2都有可能长度为0。
如果两个都为0,返回0。如果其中一个为0,返回长度之差的绝对值。
代码
class Solution {
public int minDistance(String word1, String word2) {
int[][] dp = new int[word1.length()][word2.length()];
if (word1.length() == 0 && word2.length() == 0){
return 0;
}
if (word1.length() == 0 || word2.length() == 0){
return Math.abs(word1.length() - word2.length());
}
if (word1.charAt(0) == word2.charAt(0)){
dp[0][0] = 0;
}else{
dp[0][0] = 1;
}
for (int i=1; i<word1.length(); i++){
if (word1.charAt(i) == word2.charAt(0)){
dp[i][0] = i;
}else{
dp[i][0] = dp[i-1][0] + 1;
}
}
for (int j=1; j<word2.length(); j++){
if (word2.charAt(j) == word1.charAt(0)){
dp[0][j] = j;
}else{
dp[0][j] = dp[0][j-1] + 1;
}
}
for (int i=1; i<word1.length(); i++){
for (int j=1; j< word2.length(); j++){
if (word1.charAt(i) == word2.charAt(j)){
dp[i][j] = dp[i-1][j-1];
}else{
dp[i][j] = Math.min(Math.min(dp[i-1][j], dp[i][j-1]), dp[i-1][j-1]) + 1;
}
}
}
return dp[word1.length()-1][word2.length()-1];
}
}