判断一个字符串是不是回文串
如:aba是回文串
/**
*验证子串s[left ..right] 是否为回文串
* char[] charArray:带判断的char型字符串
* int left 最左端索引
* int right 最右端索引
*/
private boolean validPalindromic(char[] charArray,int left,int right){
// 判断每一个charArray[left]是否与对应的charArray[right]相等
// 如果有一个不相等的,直接返回false,否则 left++,right--,知道left 不再小于right
// 如果判断完都没有false,那么直接返回true
while(left < right){
if(charArray[left] != charArray[right]){
return false;
}
left++;
right--;
}
//返回true
return true;
}
class Solution {
//暴力解法
/*
*String s:待判断的字符串
*/
public String longestPalindrome(String s) {
//获取字符串的长度
int len = s.length();
//如果长度是0或者1,那么直接返回字符串
if(len <2){
return s;
}
//如果字符串的长度>1
//定义一个回文串的长度的初始值为1
//定义回文串的初始索引为0
int maxLen = 1;
int begin = 0;
//s.charAt(i)每次都会检查数组下标越界,因此先转换成字符数组,这一步非必须
char[] charArray = s.toCharArray();
//枚举所有长度严格大于1的子串 charArray[i...j]
//定义两个变量i,j
// i从0开始,j从i+1开始,判断charArray[i..j]是不是回文串,并记录最大回文串的起始位置
// maxLen用于保存每一次遍历的最大回文串的长度,
//begin用于保存最大回文串的初始索引
//根据初始索引和最大长度,返回最大回文串
for(int i=0;i<len -1;i++){
for(int j=i+1;j<len;j++){
if(j-i+1 > maxLen && validPalindromic(charArray,i,j)){
maxLen = j-i+1;
begin = i;
}
}
}
return s.substring(begin,begin+maxLen);
}
private boolean validPalindromic(char[] charArray,int left,int right){
while(left < right){
if(charArray[left] != charArray[right]){
return false;
}
left++;
right--;
}
return true;
}
}
解法二:回文串
class Solution {
public String longestPalindrome(String s) {
int len = s.length();
if(len <2){
return s;
}
int maxLen = 1;
int begin = 0;
char[] charArray = s.toCharArray();
for(int i=0;i<len -1;i++){
int oddLen = expandAroundCenter(charArray,i,i);
int evenLen = expandAroundCenter(charArray,i,i+1);
int curMaxLen = Math.max(oddLen,evenLen);
if(curMaxLen >maxLen){
maxLen = curMaxLen;
//这一步要在纸上画图发现规律
begin = i-(maxLen -1) /2;
}
}
return s.substring(begin,begin+maxLen);
}
//判断是否是回文串,中心扩散法,分奇偶数
/**
* @param charArray 原始数组的字符数组
* @param left 起始左边界
* @param right 起始右边界
* @return 回文串的长度
*/
private int expandAroundCenter(char[] charArray,int left,int right){
// 当left = right 的时候,回文中心是一个字符,回文串的长度是奇数
// 当right = left + 1的时候,此时回文中心两个字符,回文串的长度是偶数
int len = charArray.length;
int i = left;
int j = right;
while(i>=0 && j<len){
if(charArray[i] == charArray[j]){
i--;
j++;
}else{
break;
}
}
//跳出while循环时,恰好满足s.charAt(i)!= s.charAt(j)
//回文串的长度是j-i+1-2 = j-i-1
return j-i-1;
}
}
动态规划解法
package leetcode.editor.cn;
/**
* 最长回文子串
* @author Cao Ziqiang
* @date 2022-09-07 09:19:59
*/
public class P5_LongestPalindromicSubstring{
public static void main(String[] args) {
//测试代码
Solution solution = new P5_LongestPalindromicSubstring().new Solution();
String s = solution.longestPalindrome("ab");
System.out.println(s);
}
//代码
//leetcode submit region begin(Prohibit modification and deletion)
class Solution {
public String longestPalindrome(String s) {
//首先判断字符长度,小于2直接返回原字符串(空,一个字符)
int len = s.length();
if(len<2){
return s;
}
//如果字符串个数>=2,初始化最大回文串的长度是1,因为就算两个字符串不同,那第一个字符串也是回文串,长度是1
//初始化回文串的起始索引是0
int maxLen = 1;
int begin = 0;
//初始化二维布尔数组dp[i][j]表示s[i..j]是否是回文串,行列都是字符串的长度,i是起始索引,j是终止索引
//注意j>=i,因此只在二维数组的对角线及右上角是合法的,对角线是单个字符
boolean[][] dp = new boolean[len][len];
//初始化:长度为1的子串都是回文串,赋值为true
for(int i = 0;i<len;i++){
dp[i][i]= true;
}
//将字符串转为char型数组
char[] charArray = s.toCharArray();
//递推开始,感觉也是暴力搜索,只是优化一下
//先枚举子串长度,长度为1的已经判断过了,现在判断长度为2的,然后依次增加
//首先遍历所有长度为2的字符串,起始位置从0开始,长度为2, 然后向后移动一位,长度为2
for(int L=2;L<=len;L++){
//枚举左边界,左边界的上限设置可以宽松一些
for(int i=0;i<len;i++){
//由L和i可以确定右边界,即j-i+1 =L得
int j = L +i -1;
//如果右边界越界,就可以退出当前循环
if(j >=len){
break;
}
//如果ij对应的字符不相同,直接赋值dp[i][j] = false
if(charArray[i] != charArray[j]){
dp[i][j] = false;
//否则,判读j-i的长度是否小于3,如果小于3,则直接赋值dp[i][j] = true
//(因为,j-i<3意味着长度<=3,在这种情况下,两端的字符相同,则一定是回文串)
//如果> 3则需要用到动态规划,判断其左下角的字符串是不是回文串
}else{
if(j-i<3){
dp[i][j] = true;
}else{
dp[i][j] = dp[i+1][j-1];
}
}
//只要dp[i][j]==true成立,就表示子串s[i..j]是回文,此时记录回文长度和起始位置
if(dp[i][j] && j-i+1 > maxLen){
maxLen = j-i+1;
begin = i;
}
}
}
//返回最大回文串
return s.substring(begin,begin+maxLen);
}
}
//leetcode submit region end(Prohibit modification and deletion)
}
ps:在条件判断中 and 是python中的,&&是java中表示关系与的,&是java中的位操作符