5. Longest Palindromic Substring Given a string s, find the longest palindromic substring in s. You may assume that the maximum length of s is 1000. Example 1: Input: "babad" Output: "bab" Note: "aba" is also a valid answer. Example 2: Input: "cbbd" Output: "bb"
给出一个字符串,得到这个字符串最大回文长度
首先先到的就是穷举法,贴下代码
public static String longestPalindrome(String s) { StringBuilder result = null; char[] charArray = s.toCharArray(); for (int i = 0; i < charArray.length; i++) { StringBuilder temp = new StringBuilder(s.substring(i, s.lastIndexOf(charArray[i]) + 1)); getPalindrome(temp, result == null ? 0 : result.length()); if (temp.length() > 0 && (result == null || temp.length() > result.length())){ result = new StringBuilder(temp); } } return result == null ? String.valueOf(s.charAt(0)): result.toString(); } private static void getPalindrome(StringBuilder temp, int resultSize){ if (temp.length() <= 1 || temp.length() <= resultSize){ return; } if (temp.toString().equals(temp.reverse().toString())){ return; } temp.deleteCharAt(0); temp.reverse(); getPalindrome(temp, resultSize); }
穷举法思路很简单,根据回文特征,从第一个字符开始,找到最后一个重复出现的位置,生成一个字符串,例如("qasqdqd"
---> "qasqdq" 判断是否是回文,如果不是,则找下一个重复出现的位置 ---> qasq 如果都不满足条件,则第一个字符就不用了,以次类推,直到找到最大长度的回文)
接下来优化的就是去掉一些无效的循环,减少循环次数:
其中StringBuilder的reverse方法频繁调用的问题,先看下StringBuilder的源码是怎么实现字符串反序的:
public AbstractStringBuilder reverse() { boolean hasSurrogates = false; int n = count - 1; for (int j = (n-1) >> 1; j >= 0; j--) { int k = n - j; char cj = value[j]; char ck = value[k]; value[j] = ck; value[k] = cj; if (Character.isSurrogate(cj) || Character.isSurrogate(ck)) { hasSurrogates = true; } } if (hasSurrogates) { reverseAllValidSurrogatePairs(); } return this; }
可以看到StringBuilder是通过循环字符串达到反序的,如果我们频繁调用reverse方法来进行回文判断,性能会受到巨大的影响,所以我们需要改变回文的判断方式。
public static String longestPalindrome(String s) { StringBuilder result = null; char[] charArray = s.toCharArray(); for (int i = 0; i < charArray.length; i++) { StringBuilder temp = new StringBuilder(s.substring(i, s.lastIndexOf(charArray[i]) + 1)); getPalindrome(temp, result == null ? 0 : result.length()); if (temp.length() > 0 && (result == null || temp.length() > result.length())){ result = new StringBuilder(temp); } } return result == null ? String.valueOf(s.charAt(0)): result.toString(); } private static void getPalindrome(StringBuilder temp, int resultSize){ if (temp.length() <= 1 || temp.length() <= resultSize){ return; } if (checkPalindrome(temp)){ return; } getPalindrome(temp.deleteCharAt(temp.length() - 1), resultSize); } private static boolean checkPalindrome(StringBuilder temp){ char[] charArrays = temp.toString().toCharArray(); int end = charArrays.length / 2 - 1; for (int i = 0; i <= end; i++) { if (charArrays[i] != charArrays[charArrays.length - i - 1]){ return false; } } return true; }
如果还要再进行优化的话,会发现需要把大量的系统方法改成自己编写的,费事费力,但是在做项目的时候,实现需求才是第一位的,在项目的实现过程中,安全性和性能都只能给业务让步,所以在没有想到更好的实现方式之前,最起码得把功能给实现出来。
但是如果需求对性能也有要求时,那就需要去寻找更加符合要求的解法,穷举法虽然在实现中是最简单也是最容易想到的方法,但是我们发现需要优化的地方实在太多太多了,这个时候就需要换一种思路进行解题。