题目分析:
给定一个字符串,判断是不是回文字符串及求它的最长回文子串的长度。
回文判断:
1.同时从字符串头尾开始向中间扫描字串,如果所有字符都一样,那么这个字符串就是一个回文。采用这种方法的话,我们只需要维护头部和尾部两个扫描指针即可。时间复杂度:O(n),空间复杂度:O(1)
//定义两个指针从首尾开始往中间靠近
private static boolean isHuiwen(String str) {
int from = 0;
int end = str.length() - 1;
if (str.isEmpty()) {
return false;
}
while (from < end) {
if (str.charAt(from) != str.charAt(end)) {
return false;
}
from++;
end--;
}
return true;
}
2. 先从中间开始、然后向两边扩展查看字符是否相等。
//从中间开始、然后向两边扩展
private static boolean isHUiwenPro(String str) {
int middle = ((str.length() >> 1) - 1) >= 0 ? (str.length() >> 1) - 1 : 0;
int first = middle;//中间位置前一个元素
int second = str.length() - 1 - middle;//中间位置后一个元素
while (first >= 0 && second <str.length()) {
if (str.charAt(first) != str.charAt(second)) {
return false;
}
first--;
second++;
}
return true;
}
最长回文子串
1.双重for循环遍历字符串,判断i-j位置的字符是否是回文,如果是,变量begin记录下i的位置,len记录下长度(j-i+1)。要最长的回文字符串,就要把每一次判断为回文的字符串长度与之前所记录的len比较,大于才满足。最后通过begin和len来截取字符串。
//通过操作i和j两个指针来参与循环
public static String LongestPalindrome(String str) {
int longestlens = 0, begin = 0;
for (int i = 0; i < str.length(); i++) {
for (int j = 0; j < str.length(); j++) {
if (isHUiwenPro(str, i, j) && j - i + 1 > longestlens) {//子串长度比longestlens小,那么他不可能是最长回文子串了
longestlens = j - i + 1;
begin = i;
}
}
}
System.out.println("最长回文子串的长度为:" + longestlens);
return str.substring(begin, begin + longestlens);
}
2.如果一段字符串是回文,那么以某个字符为中心的前缀和后缀都是相同的,那么,我们可以枚举中心位置,然后再在该位置上用扩展法,记录并更新得到的最长的回文长度。该方法要讨论字符串的奇偶情况,因此要分别计算出奇偶下的回文子串长度并取最大值。
//枚举中心位置然后分别往前后扩展
public static String longestPalindrome(String s) {
if (s.length() < 2) {
return s;
}
int maxLen = 0;//最大长度
int begin = 0;//开始截取位置
//char[0] char[len-1] 时是第一个和最后一个元素,无法左扩展和无法右扩展,排除这俩个元素。
for (int i = 1; i < s.length() - 1; i++) {
//回文子串长度为奇数,初始子串为一个字符charAt(i)
int oddLen = isHuiWenShu(s, i, i);
//回文子串长度为偶数,初始子串为charAt(i)和charAt(i+1),i<len-1,i+1不会下标越界
int evenLen = isHuiWenShu(s, i, i + 1);
//取奇偶情况下的当前最长回文子串
int curMaxLen = Math.max(oddLen, evenLen);
//比当前存储最长回文子串长,重新存储
if (curMaxLen > maxLen) {
// 当回文子串为偶数,一定是i右边多一个字符。
// 所以左边长度要减1
// 回文字符串奇数时 int/2取整 -1也不影响结果
maxLen = curMaxLen;
begin = i - (maxLen - 1) / 2;
}
}
return s.substring(begin, begin + maxLen);
}
public static int isHuiWenShu(String str, int left, int right) {
while (left >= 0 && right < str.length() && str.charAt(left) == str.charAt(right)) {
left--;
right++;
}
return right - left - 1;
}
3.O(N)解法。参考Manacher's ALGORITHM: O(n)时间求字符串的最长回文子串 - Felix021 - So far so good 。