LeetCode 第五题 最长回文子串(Longest Palindromic Substring)

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

  • 示例 1:
    输入: “babad”
    输出: “bab”
    注意: "aba"也是一个有效答案。
  • 示例 2:
    输入: “cbbd”
    输出: “bb”

思路:可以从头到尾遍历每个字符串,然后从中间向外扩展,判断最大能扩展到的长度。即:例如“babad”这种串,通过遍历,b,a,b,a,d,的顺序,每次遍历到一个字符,将其作为字符串的最中间,向两端扩展,例如当遍历到第一个a时,向两端扩展,bab,判断扩展的两个字符是否相等。还有一种情况就是回文子串长度是偶数。例如示例二中的“bb”,因此,这里再遍历一次,这次的遍历方式跟上面一样,只是中间的变成了两个字符,且要判断两个字符是否相等。代码:

	private static String longestPalindrome(String s) {
		// 对输入进行判断
        if (s == null) {
            return null;
        }
        int left = 0, right = 0;
        String oddString = "", evenString = "";
        // 如果回文字串为奇数
        for (int i = 0; i < s.length(); i++) {
            left = i - 1;
            right = i + 1;
            // 进行左右扩展
            while (check(left, right, s)) {
                left--;
                right++;
            }
            // 当没有办法扩展时,判断这时的字串长度与原最长奇字串进行比较
            if (oddString.length() < (right - i - 1) * 2 + 1) {
                oddString = s.substring(left + 1, right);
            }
        }

        // 如果回文字串为偶数
        for (int i = 0; i < s.length() - 1; i++) {
        	// 这里判断最中间的两个元素是否相等
            if (!check(i, i + 1, s)) {
                continue;
            }
            left = i - 1;
            right = i + 2;
            while (check(left, right, s)) {
                left--;
                right++;
            }
            if (evenString.length() < (right - i - 1) * 2) {
                evenString = s.substring(left + 1, right);
            }
        }
        // 最后判断 长度为奇数的最长字串 跟 长度为偶数的最长字串 两个的大小关系
        return oddString.length() > evenString.length()? oddString: evenString;
    }

    private static boolean check(int i, int j, String s) {
        if (i < 0 || j >= s.length()) {
            return false;
        }
        return s.substring(i , i + 1).equals(s.substring(j, j + 1));
    }

这个代码是可以通过的,但执行的速度比较慢,下图是在LeetCode中文网上提交的结果:
在这里插入图片描述
因此,这里提出一个改进的方案:就是当遍历到第i个节点,要遍历i + 1节点时,先判断以第i + 1节点为中点时,长度为当前最长字串长度的字串,是否是回文字符串,如果是,则继续扩展,不是则遍历下一个节点,代码:

	private static String longestPalindrome_(String s) {
        if (s == null) {
            return null;
        }
        int left = 0, right = 0;
        String oddString = "", evenString = "";
        // 如果回文字串为奇数
        for (int i = 0; i < s.length(); i++) {
        	// 先判断以当前节点为中心,能否获得当前已知的最长字串
            left = i - oddString.length() / 2;
            right = i + oddString.length() / 2;
            if (!check_(left, right, s)) {
                continue;
            }
            while (check(left, right, s)) {
                left--;
                right++;
            }
            if (oddString.length() < (right - i - 1) * 2 + 1) {
                oddString = s.substring(left + 1, right);
            }
        }

        // 如果回文字串为偶数
        for (int i = 0; i < s.length() - 1; i++) {
            if (!check(i, i + 1, s)) {
                continue;
            }
            left = i - evenString.length() / 2;
            right = i + evenString.length() / 2 + 1;
            if (!check_(left, right, s)) {
                continue;
            }
            while (check(left, right, s)) {
                left--;
                right++;
            }
            if (evenString.length() < (right - i - 1) * 2) {
                evenString = s.substring(left + 1, right);
            }
        }
        return oddString.length() > evenString.length()? oddString: evenString;
    }

	private static boolean check(int i, int j, String s) {
        if (i < 0 || j >= s.length()) {
            return false;
        }
        return s.substring(i , i + 1).equals(s.substring(j, j + 1));
    }

    private static boolean check_(int i, int j, String s) {
        if (i < 0 || j >= s.length()) {
            return false;
        }
        StringBuilder sb = new StringBuilder(s.substring(i, j + 1));
        String temp = sb.reverse().toString();
        return temp.equals(s.substring(i, j + 1));
    }

速度提升了很多,但还有很大提升空间,博主暂时没有其他好的改进方案:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/Applying/article/details/82982244