zoukankan      html  css  js  c++  java
  • 子串、子序列问题

    子串、子序列问题

    字符串

    最长公共子序列

    dp[i] [j] 表示以下标i结尾的str1 和 以下标j结尾的str2的最长公共子序列的长度。

    dp[i] [j]=

    1. 0, i=0或者j=0
    2. dp[i-1] [j-1]+1, str[i-1]==str[j-1]
    3. max( dp[i-1] [j], dp[i] [j-1] ), str[i-1]!=str[j-1]
    public int longestCommonSubsequence(String text1, String text2) {
        if (text1 == null || text2 == null) {
            return 0;
        }
        int len1 = text1.length();
        int len2 = text2.length() ;
        int[][] dp = new int[len1+1][len2+1];
        for (int i = 1; i <=len1; i++) {
            for (int j = 1; j <=len2; 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[len1][len2];
    
    }
    

    最长公共子串

    dp[i] [j] 表示以下标i结尾的str1 和 以下标j结尾的str2的最长公共子串的长度。

    dp[i] [j]=

    1. 0, i=0或者j=0
    2. dp[i-1] [j-1]+1, str1[i-1]==str2[j-1]
    3. 0, str1[i-1]!=str2[j-1]
    public int longestCommonSubStr(String text1, String text2) {
        if (text1 == null || text2 == null) {
            return 0;
        }
        int res = 0;
        int len1 = text1.length();
        int len2 = text2.length();
        int[][] dp = new int[len1 + 1][len2 + 1];
        for (int i = 1; i <= len1; i++) {
            for (int j = 1; j <= len2; j++) {
                if (text1.charAt(i - 1) == text2.charAt(j - 1)) {
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                }
                res = Math.max(dp[i][j], res);
            }
        }
        return res;
    
    }
    

    最长不含重复字符的子字符串

    滑动窗口:

    1. 刚开始right向右移动,同时更新max。直到出现了重复字符a,right停止移动,然后left向右移动,滑动窗口减小
    2. 当窗口中没有重复字符a时,left停止移动,更新max。
    3. 重复上述过程,直到字符串结尾。

    image-20200310201308128

    public int lengthOfLongestSubstring_1(String s) {
     if (s.length() == 0 || s == null) {
         return 0;
     }
     char[] chars = s.toCharArray();
     Map<Character, Integer> windows = new HashMap<>();
     int left = 0;
     int right = 0;
     int res = 0;
     //每次移动right,增大滑动窗口时更新res
     for (int i = 0; i < chars.length; i++) {
         windows.put(chars[i], windows.getOrDefault(chars[i], 0) + 1);
         right++;
         while (windows.get(chars[i]) > 1) {
             char c = chars[left];
             windows.put(c, windows.get(c) - 1);
             left++;
         }
         res = Math.max(res, right - left);
    
     }
     return res;
    }
    
    

    最长回文子序列

    dp[i] [j] 表示从i到j的最长回文子序列的长度

    状态转移方程

    dp[i] [j] = dp[i+1] [j-1] + 2 , s[i] == s[j]

    dp[i] [j] = max(dp[i] [j-1] , dp[i+1] [j]) ,s[i] != s[j]

    //    动态规划,状态转移方程
    public int longestPalindromeSubseq(String s) {
        if (s == null || s.length() == 0) {
            return 0;
        }
    
        int[][] dp = new int[s.length()][s.length()];
        //        初始化
        for (int i = 0; i < dp.length; i++) {
            dp[i][i] = 1;
        }
    
        //        状态转移方程
        for (int i = dp.length - 2; i >= 0; i--) {
            for (int j = i + 1; j < dp[i].length; j++) {
                if (s.charAt(i) == s.charAt(j)) {
                    dp[i][j] = dp[i + 1][j - 1] + 2;
                } else {
                    dp[i][j] = Math.max(dp[i][j - 1], dp[i + 1][j]);
                }
            }
        }
    
        return dp[0][s.length() - 1];
    
    
    }
    

    最长回文子串

    从中间向两边扩散来判断回文串,需要考虑字符串是奇数还是偶数,因为两者的中心不同。

    // 中心扩散法,时间复杂度O(n^2)
    public String longestPalindrome(String s) {
        if (s == null || s.length() == 0) {
            return s;
        }
    
        String res = "";
        for (int i = 0; i < s.length(); i++) {
            String s1 = expandCenter(s, i, i);
            String s2 = expandCenter(s, i, i + 1);
            res = s1.length() > res.length() ? s1 : res;
            res = s2.length() > res.length() ? s2 : res;
    
        }
    
        return res;
    
    }
    
    public String expandCenter(String s, int left, int right) {
        while (left >= 0 && right < s.length() && s.charAt(left) == s.charAt(right)) {
            left--;
            right++;
        }
        return s.substring(left + 1, right);
    }
    

    数组

    动态规划

    最长递增子序列

    dp[i]表示以i结尾的数组的最长递增子序列的长度

    dp[i]=

    1. max( dp[j]+1 ) , nums[i]>nums[j] , 0<=j<i
    2. 1 , nums[i]<=nums[j]
    class Solution {
        public int lengthOfLIS(int[] nums) {
            if(nums.length==0||nums==null){
                return 0;
            }
            int n=nums.length;
            int[] dp=new int[n];
            Arrays.fill(dp,1);
            for(int i=0;i<n;i++){
                for(int j=0;j<i;j++){
                    if(nums[i]>nums[j]){
                        dp[i]=Math.max(dp[j]+1,dp[i]);
                    }
                }
            }
            int maxLen=0;
            for(int i=0;i<n;i++){
                maxLen=Math.max(maxLen,dp[i]);
            }
            return maxLen;
    
        }
    }
    

    最长递增子序列的个数

    count[i] 表示以i结尾的数组最长递增子序列的个数

    count[i] =

    当nums[i] > nums[j] , 0<=j<i时

    dp[j]+1==dp[i], count[i]=count[j]+count[i]

    dp[j]+1>dp[i], count[i] = count[j]

    class Solution {
        public int findNumberOfLIS(int[] nums) {
            if(nums.length==0||nums==null){
                return 0;
            }
            int n=nums.length;
            int[] dp=new int[n];
            int[] count=new int[n];
            Arrays.fill(dp,1);
            Arrays.fill(count,1);
            
            for(int i=0;i<n;i++){
                for(int j=0;j<i;j++){
                    if(nums[i]>nums[j]){
                        if(dp[j]+1==dp[i]){
                            count[i]+=count[j];
                        }
                        if(dp[j]+1>dp[i]){
                            count[i]=count[j];
                        }
                        dp[i]=Math.max(dp[j]+1,dp[i]);
                        
                    }
                }
            }
            int maxLen=0;
            for(int i=0;i<n;i++){
                maxLen=Math.max(maxLen,dp[i]);
            }
            return maxLen;
    
        }
    }
    

    最长递增子串

    dp[i] 表示以i结尾的数组最长递增子串的长度

    dp[i]=

    1. dp[i-1] +1 , nums[i]>nums[i-1], 1<=i<n
    2. 1 , nums[i]<=nums[i-1], 1<=i<n
    public int findLengthOfLCIS(int[] nums) {
        if (nums.length == 0 || nums == null) {
            return 0;
        }
        if (nums.length == 1) {
            return 1;
        }
        int n = nums.length;
        int[] dp = new int[n];
        Arrays.fill(dp, 1);
        int res = 0;
        for (int i = 1; i < n; i++) {
            if (nums[i] > nums[i - 1]) {
                dp[i] = dp[i - 1] + 1;
            }
            res = Math.max(res, dp[i]);
        }
        return res;
    
    }
    
  • 相关阅读:
    不要让生命的车轮停下,否则再次驱动需要更多的力气
    计算机英语
    知我者谓我心忧,不知我者谓我何求
    Poverty in USA and China
    [转]PCI配置空间简介
    基于OpenGL的起重机模拟
    OpenGL 彩色旋转立方体
    asp.net下载文件几种方式
    Jquery+$.cookie()实现跨越页面tabs导航
    简单自定义实现jQuery验证
  • 原文地址:https://www.cnblogs.com/dockerchen/p/12458709.html
Copyright © 2011-2022 走看看