对给定的字符串,本题要求你输出最长对称子串的长度。例如,给定Is PAT&TAP symmetric?,最长对称子串为s PAT&TAP s,于是你应该输出11。
输入格式:
输入在一行中给出长度不超过1000的非空字符串。
输出格式:
在一行中输出最长对称子串的长度。
输入样例:
Is PAT&TAP symmetric?
输出样例:
11
解题思路
- 寻找最长回文子串:
主要逻辑在longestPalindromeLength方法中实现。此方法接收一个字符串作为输入,并返回最长回文子串的长度。 - 中心扩展算法:
对于给定的字符串,该方法通过expandAroundCenter辅助方法实现中心扩展算法,对字符串中的每个字符尝试两种情况:
-> 奇数长度的回文:以字符本身为中心。
-> 偶数长度的回文:以字符及其右侧字符为中心。
在每种情况下,它尝试向左右扩展,直到不能形成更大的回文子串为止。 - 计算并更新最长回文长度:
->每次中心扩展检查后,算法会比较这次扩展得到的回文长度与之前找到的最长回文长度。
->如果新的回文更长,它会更新最长回文的起始和结束位置。 - 返回结果:
最后,算法计算并返回最长回文子串的长度,这是通过计算end - start + 1得到的,其中start和end分别是最长回文子串在原字符串中的起始和结束位置的索引。 - expandAroundCenter方法:
-> 这个辅助方法接受三个参数:原字符串s、左起始索引left和右起始索引right。
-> 它尝试向左和向右扩展,直到遇到不匹配的字符或达到字符串的边界。
-> 每当左右字符匹配时,它就将左索引向左移动一位,将右索引向右移动一位,继续比较。
-> 最终,这个方法返回找到的回文子串的长度。
解题代码
import java.util.ArrayList;
import java.util.Scanner;
public class Main{
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String input = scanner.nextLine();
// 输出最长对称子串的长度
System.out.println(longesPalindromeLength(input));
scanner.close();
}
private static int longesPalindromeLength(String input) {
if(input == null || input.length() < 1){
return 0;
}
int start = 0, end = 0;
for (int i = 0; i < input.length(); i++) {
int len1 = expandAroundCenter(input, i ,i); // 奇数长度的回文
int len2 = expandAroundCenter(input, i, i+1); // 偶数长度的回文
int len = Math.max(len1,len2);
/**
* 找到更长的回文子串时更新最长回文子串的起始和结束位置。
* 「len」是当前找到的回文子串的长度。这个长度是通过expandAroundCenter方法计算得到的,它可以是以当前字符为中心的奇数长度回文或是以当前字符及其下一个字符为中心的偶数长度回文。
* 「if (len > end - start)」判断当前找到的回文子串是否比之前记录的最长回文子串更长。
*/
if( len > end - start){
/**
* 如果找到了更长的回文,start 和 end 将根据当前中心点i和回文长度len进行更新。
* 由于回文是对称的,我们可以通过当前中心点和回文长度计算出新的起始和结束位置:
* 「start = i - (len - 1)/2」 计算新的回文起始位置。对于奇数长度的回文,(len - 1) / 2正好是中心点到回文开始的距离。对于偶数长度的回文,由于中心是两个字符之间的位置,这个计算同样适用。
* 「end = i + len / 2」计算新的回文结束位置。这个计算逻辑与计算起始位置相似,只是方向相反。
*/
start = i - (len - 1)/2;
end = i + len /2;
}
}
return end - start + 1;
}
private static int expandAroundCenter(String s, int left, int right){
while (left >= 0 && right < s.length() && s.charAt(left) == s.charAt(right)){
/**
* 双指针技巧
*/
left--;
right++;
}
// 当需要跳出循环时,需要多+1才能跳出来,所以结果需要-1
return right - left - 1;
}
}