打卡代码随想录Day17

1.最长公共子序列(力扣1143)

本题重点在于状态的转移,以dp[i][j]表示在第一个字符串中下标为i的字符前和在第二个字符串中下标为j的字符前最长的公共子序列长度。若当前两字符相等,有dp[i][j] = dp[i-1][j-1]+1,若不相等,有dp[i][j] = Math.max(dp[i-1][j],dp[i][j-1])。

public int longestCommonSubsequence(String text1, String text2) {
    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()];
}

2.不相交的线(力扣1035)

本题与上题可以说一模一样,都是寻找最长公共子序列,但是这道题要与力扣上第718题区别开,力扣上第718题要求最长重复(公共)子数组,是要求连续的,本题可以不连续,故状态转移时不一样。对于本题:

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]);

对于力扣上第718题:

if(nums1[i-1] == nums2[j-1])
    dp[i][j] = dp[i-1][j-1] + 1;

并且在收集结果时,本题直接返回dp[nums1.length][nums2.length],718题要返回过程中最大的dp[i][j]。

public int maxUncrossedLines(int[] nums1, int[] nums2) {
    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];
}

3.最大子数组和(力扣53)

之前在学习贪心时已经做过这道题,这次再遇到就用贪心和DP两个方法做。

    public int maxSubArray(int[] nums) {
//        //贪心
//        int sum = 0;
//        int max = Integer.MIN_VALUE;
//        for (int i = 0; i < nums.length; i++) {
//            sum += nums[i];
//            if(sum > max)
//                max = sum;
//            //负数只会拖累结果
//            if(sum < 0)
//                sum = 0;
//        }
//        return max;
        //DP,dp[i]记录到第i个位置结束时的最大和
        int[] dp = new int[nums.length];
        dp[0] = nums[0];
        //避免从第一个数开始就是一个全部都是负数的递减序列,让最大值是第一个数
        int max = nums[0];
        for (int i = 1; i < nums.length; i++) {
            if (dp[i-1] > 0)
                dp[i] = dp[i-1]+nums[i];
            else
                dp[i] = nums[i];
            if(dp[i] > max)
                max = dp[i];
        }
        return max;
    }

4.判断子序列(力扣392)

本题可以通过双指针循环一次得到结果,也可以用动态规划判断最长子序列的长度是否等于子序列长度。

public boolean isSubsequence(String s, String t) {
//        //DP解法
//        int[][] dp = new int[s.length()+1][t.length()+1];
//        for (int i = 1; i <= s.length(); i++) {
//            for (int j = 1; j <= t.length(); j++) {
//                if(s.charAt(i-1) == t.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[s.length()][t.length()] == s.length();
        //双指针解法
        int left = 0;
        int right = 0;
        while (left != s.length() && right != t.length())
        {
            if(s.charAt(left) == t.charAt(right))
            {
                left++;
                right++;
            }
            else
                right++;
        }
        return left == s.length();
    }
        //DP解法2,就是两比较元素若不相等则只用等于这一行的前一个
//        int[][] dp = new int[s.length()+1][t.length()+1];
//        for (int i = 1; i <= s.length(); i++) {
//            for (int j = 1; j <= t.length(); j++) {
//                if(s.charAt(i-1) == t.charAt(j-1))
//                    dp[i][j] = dp[i-1][j-1] + 1;
//                else
//                    dp[i][j] = dp[i][j-1];
//            }
//        }
//        return dp[s.length()][t.length()] == s.length();
//    }

*5.回文子串(力扣647)

首先用暴力求解,对于每个子串都遍历一次,若是回文子串则res++。然后用中心扩散法,此方法难点在于作为中心的节点会有2*s.length()-1个(包括s.length个单独节点和s.length-1个相邻的两个节点)这样就保证了遇到ababa时以任何单一节点为中心都无法检测子串abab是否为回文串的尴尬,以ba为中心就可以向两边扩展得到abab,故以2*s.length()-1个节点为中心向两边扩展,遇到回文串时res++,已经不是回文串时直接跳出该次循环,遍历下一个中心。

//    //暴力解法
//    public int countSubstrings(String s) {
//        int res = 0;
//        for (int i = 0; i < s.length(); i++) {
//            for (int j = i+1; j < s.length()+1; j++) {
//                if(isHuiWen(s.substring(i,j)))
//                    res++;
//            }
//        }
//        return res;
//    }
//    public boolean isHuiWen(String s){
//        if(s.length() == 0)
//            return true;
//        for (int i = 0,j = s.length()-1; i < j; i++,j--) {
//            if(s.charAt(i) != s.charAt(j))
//                return false;
//        }
//        return true;
//    }
    //双指针法,共有2*s.length-1个中心,从中心向两边扩散,记录回文子串数目
    public int countSubstrings(String s){
        int res = 0;
        int left = 0;
        int right = 0;
        for (int i = 0; i < 2 * s.length() - 1; i++) {
    //保证一共2*s.length-1个中心都能遍历到
            left = i / 2;
            right = left + i % 2;
            while (left >= 0 && right <= s.length()-1){
                if(s.charAt(left) == s.charAt(right)){
                    res++;
                    left--;
                    right++;
                }
                //已经不是回文了
                else
                    break;
            }
        }
        return res;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值