【每日刷题】代码随想录-动规41、42、43、44、50

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. 最长连续递增序列

两个思路:

  1. 动规 dp[i]表示到nums[i]的最长连续递增序列,不用dp[j]了,if (nums[i] > nums[1]),则dp[i] = dp[i-1]+1。初始化dp[i]都等于1。
  2. 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): 可增,可删,可替换,因此又分三种情况

  1. 【增】word1的索引i处增加一个与word2索引j相同的字符:dp[i-1][j] +1
  2. 【删(=增)】word1的索引i处减少字符(又等于word2增加字符):dp[j-1][i]+1
  3. 【替换】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];
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值