zoukankan      html  css  js  c++  java
  • 求最长回文串

    题目描述如下:

    能立刻想到的就是爆破,先试试无脑爆破,时间复杂度O(n^3),然后毫无意外的超时了,爆破代码如下:

    public String longestPalindrome(String s) {
            
            int max = 0;
            int length = s.length();
            // 字符串长度只有1个或为空,那么它自身就是回文串
            if (length <= 1) {
                return s;
            }
            
            String rtString = "";
            // 从第一个字符开始,统计以每个字符开头的能达到的最大回文子串
            for (int i = 0; i < length; i++) {
                for (int j = i + 1; j < length; j++) {
                    
                    String subStr = s.substring(i, j + 1);
                    int left = 0;
                    int right = subStr.length() - 1;
                    boolean flag = true;
                    // 判断是不是回文子串
                    while (left <= right) {
                        if (subStr.charAt(left) == subStr.charAt(right)) {
                            left++;
                            right--;
                        }else {
                            flag = false;
                            break;
                        }
                    }
                    int size = subStr.length();
                    // 进行最大长度记录
                    if (flag && size > max) {
                        max = size;
                        rtString = subStr;
                    }
                }
            }
            
            if (max == 0) {
                rtString = s.charAt(0) + "";
            }
            
            return rtString;
    }
    View Code

    然后思考怎么使用动态规划,无奈本人动态规划渣渣,于是看题解

    给出定义如下

    那么
    
    P(i, j)=(P(i+1,j−1) and Si​==Sj​)
    
    P(i,i)=true
    
    P(i, i+1) = ( S_i == S_{i+1} )P(i,i+1)=(Si​==Si+1​)
    

    恍然大悟,然后开始编码,动态规划算法代码如下:

    public String longestPalindrome1(String s) {
            
            if (s.length() <= 1) {
                return s;
            }
            
            int length = s.length();
            boolean[][] dp = new boolean[length][length];
            // 初始化单一字符为回文串
            for (int i = 0; i < dp.length; i++) {
                dp[i][i] = true;
            }
            
            // 因为dp[i][j]取决于d[i+1][j-1]的状态,所以自底向上进行动态规划
            for (int i = length - 1; i >= 0; i--) {
                for (int j = i; j < dp[i].length; j++) {
                    if (j - i < 2) { //两个字符相邻或者就是同一个字符
                        dp[i][j] = (s.charAt(i) == s.charAt(j));
                    }else { // 字符 i~j 是否为回文取决于 i+1 ~ j-1是否为回文 及 s[i] 是否等于 s[j]
                        dp[i][j] = (dp[i + 1][j - 1] && s.charAt(i) == s.charAt(j));
                    }
                }
            }
            
            // 遍历dp数组找到最长回文串
            int maxlength = 0;
            int maxi = 0;
            int maxy = 0;
            for (int i = 0; i < dp.length; i++) {
                for (int j = i; j < dp.length; j++) {
                    if (dp[i][j]) {
                        int len = j - i + 1;
                        if (len > maxlength) {
                            maxlength = len;
                            maxi = i;
                            maxy = j;
                        }
                    }
                }
            }
            
            return s.substring(maxi, maxy + 1);
        }
    View Code

    继续看看还有什么算法,看到中心扩展法,即以某个字符为中心向两边扩展,时间复杂度为O(n^2)代码如下:

    public String longestPalindrome2(String s) {
            
            int length = s.length();
            if (length <= 1) {
                return s;
            }
            
            int max = 0;
            int startIndex = 0;
            // 这轮循环时计算
            for (int i = 0; i < length; i++) {
                
                int left = i;
                int right = i;
                
                // 求得回文串长度为奇数的串,返回值为{回文串串长度,回文串开始下标}
                int[] jiCuan = getCuan(s, left, right);
                // 求得回文串长度为偶数的串,返回值为{回文串串长度,回文串开始下标}
                int[] ouCuan = getCuan(s, left, right + 1);
                
                int bigger = 0;
                if (jiCuan[0] > ouCuan[0]) {
                    bigger = jiCuan[0];
                    left = jiCuan[1];
                }else {
                    bigger = ouCuan[0];
                    left = ouCuan[1];
                }
                
                if (bigger > max) {
                    max = bigger;
                    startIndex = left;
                }
            }
            return s.substring(startIndex, startIndex + max);
        }
        
        public int[] getCuan(String s, int left, int right) {
            // s[left](奇数回文串时)或s[left]~s[right](偶数回文串时)为中心向两边扩展
            while (left >= 0 && right < s.length()) {
                if (s.charAt(left) == s.charAt(right)) {
                    left--;
                    right++;
                }else {
                    break;
                }
            }
            // 循环退出之前会把left-1,right+1,所以分别要加回来和减出去
            left = left + 1;
            right = right - 1;
            int[] a = {right - left + 1, left};
            return a;
        }
    View Code

    还有一种算法,比较难想到,时间复杂度为O(n),人称“马拉车算法”,这里给出参考链接:

    https://www.cnblogs.com/grandyang/p/4475985.html

  • 相关阅读:
    看K线学炒股(8.10)
    看K线学炒股(8.9)
    看K线学炒股(8.5)
    看K线学炒股(0803)
    看K线学炒股(7.29)
    看K线学炒股(7.21)
    看K线学炒股(2021.07.20)
    看K线学炒股
    说说英力特这只股票
    matlab里的数据转换到Python中去的一个问题
  • 原文地址:https://www.cnblogs.com/X-huang/p/10785545.html
Copyright © 2011-2022 走看看