美文网首页
5. 最长回文子串

5. 最长回文子串

作者: 间歇性发呆 | 来源:发表于2020-01-05 16:24 被阅读0次

    给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。

    示例 1:

    输入: "babad"
    输出: "bab"
    注意: "aba" 也是一个有效答案。
    示例 2:

    输入: "cbbd"
    输出: "bb"

    来源:力扣(LeetCode)
    链接:https://leetcode-cn.com/problems/longest-palindromic-substring
    著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

    动态规划,但是时间复杂度O(n^2),勉强跑过

    class Solution {
        private static final String EMPTY = "";
    
        /**
         * 动态规划
         *
         * 1. 状态定义
         *  f(x) = 以x元素坐标为中心的回文
         * 2. 状态转移方程
         *  f(x) = f(2 * x - i) + f(x) + f(i), x = 0 ~ i
         *
         * 时间复杂度O(n^2),此解超时
         *
         * @param s
         * @return
         */
        public String longestPalindrome(String s) {
            int len = s.length();
            // 加上这个判断勉强跑过了
            if (len == 0 || s.replace(String.valueOf(s.charAt(0)), "").length() == 0) {
                return s;
            }
            String[] palindrome = new String[2 * len + 1];
            String max = "";
            for (int i = 0; i < 2 * len + 1; i++) {
                char iCh = getChar(s, i);
                setChar(palindrome, s, i);
                for (int j = 0; j <= i; j++) {
                    int before = 2 * j - i;
                    if (before < 0 || getChar(s, before) != iCh || !needPalindrome(j, i, palindrome[j])) {
                        continue;
                    }
                    palindrome[j] = iCh + (palindrome[j] == null ? "" : palindrome[j]) + iCh;
                    if (palindrome[j].length() > max.length()) {
                        max = palindrome[j];
                    }
                }
            }
            return max.replace(String.valueOf(Character.MIN_VALUE), "");
        }
    
        /**
         * 只有连续的元素是回文才能算是回文
         *
         * @param position 回文中心
         * @param index 最外的字符
         * @param palindrome 当前的回文
         * @return
         */
        private boolean needPalindrome(int position, int index, String palindrome) {
            int curLen = palindrome == null ? 0 : palindrome.length();
            return index - position == curLen / 2 + 1;
        }
    
        /**
         * index是填充后的坐标,s是为填充的字符串,获取对应的字符需要进行转换
         *
         * @param s
         * @param index
         * @return
         */
        private char getChar(String s, int index) {
            if (index % 2 == 0) {
                return Character.MIN_VALUE;
            }
            return s.charAt(index / 2);
        }
    
        private void setChar(String[] palindrome, String s, int index) {
            if (index % 2 == 0) {
                palindrome[index] = EMPTY;
            } else {
                palindrome[index] = String.valueOf(s.charAt(index / 2));
            }
        }
    }
    
    运行效率

    动态规划v2

    class Solution {
        /**
         * 动态规划
         *
         * 1. 状态定义
         *  f[begin][end]: 坐标i到j字符串是否是回文
         *
         * 2. 状态转移方程
         *  f[begin][end] = f[begin+1][end-1] && (s[begin] == s[end]), (begin <= end)
         *
         * @param s
         * @return
         */
        public String longestPalindrome(String s) {
            if (s.length() == 0) {
                return s;
            }
            int maxLen = 1, maxLeft = 0, maxRight = 0;
            boolean[][] f = new boolean[s.length()][s.length()];
            // 初始状态
            for (int i = 0; i < s.length(); i++) {
                // 单个元素都是回文
                f[i][i] = true;
            }
            for (int end = 1; end < s.length(); end++) {
                for (int begin = 0; begin < end; begin++) {
                    if (s.charAt(begin) != s.charAt(end)) {
                        continue;
                    }
                    if (end - begin < 3 || f[begin + 1][end - 1]) {
                        f[begin][end] = true;
                        if (end - begin + 1 > maxLen) {
                            maxLen = end - begin + 1;
                            maxLeft = begin;
                            maxRight = end;
                        }
                    }
                }
            }
            return s.substring(maxLeft, maxRight + 1);
        }
    }
    
    运行效率

    类似动态规划,比较优的O(n^2)算法

    class Solution {
        private int maxLen = 1; // 最大长度
        private int resLeft = 0;
        private int resRight = 0;
    
        /**
         * 分别以每个节点为中心进行扩散,记录最大的回文
         *
         * @param s
         * @return
         */
        public String longestPalindrome(String s) {
            if (s.length() == 0) {
                return s;
            }
            for (int i = 0; i < s.length(); i++) {
                // 以i为中心,奇数元素的回文
                searchPalindrome(s, i - 1, i + 1);
                // 以i和i+1为中心,偶数元素的回文
                searchPalindrome(s, i, i + 1);
            }
            return s.substring(resLeft, resRight + 1);
        }
    
        private void searchPalindrome(String s, int left, int right) {
            while (left >= 0 && right < s.length() && s.charAt(left) == s.charAt(right)) {
                left--;
                right++;
            }
            if (right - left - 1 > maxLen) {
                maxLen = right - left - 1;
                resLeft = left + 1;
                resRight = right - 1;
            }
        }
    }
    
    运行效率

    时间复杂度O(n)的Manacher算法,难度较大,还未实现

    相关文章

      网友评论

          本文标题:5. 最长回文子串

          本文链接:https://www.haomeiwen.com/subject/qaztactx.html