示例一:
输入:s = "babad"
输出:"bab"
解释:"aba" 同样是符合题意的答案。
示例二:
输入:s = "cbbd"
输出:"bb"
这道题我给出了2个思路,四种解法,一种思路是暴力解法,一种用到了动态规划
1、第一种思路 暴力解法
解法一:
当输入的字符串长度为0或者为1的时候,则它的最大回文字串就是它本身;如果大于这个长度,我是这样思考的:
用两个指针分别从第一个字母和最后一个字母进行遍历,当首指针与与尾指针相同的时候,可能他们之间是最长的回文字串,这时将首指针向后移动,尾指针向前移动一位,再次进行判断他们所指向的字符是否相同,相同就继续移动指针,不同则最初的首位指针向后一步继续遍历;如果一直相同知道尾指针的下表不在小于首指针,则这是判断最初判断的首尾指针之间的字符串为回文字串,记录字串。然后一次进行比较,最后找出最大的字串返回。这种方法虽然能够解出来,但是会有几个测试用例超时,毕竟太暴力了。
public static String longestPalindrom (String string) {
//当字符串长度为0或者为1的时候,返回它本身
if (string.length()<2){
return string;
}
String max=string.substring(0,1);
for (int i = 0; i < string.length(); i++) {
String test = "";
for (int j = string.length()-1; j >i; j--) {
if (string.charAt(i)==string.charAt(j)){
int a = i+1;
int b= j-1;
boolean flag=true;
while (b>a){
if (string.charAt(b)==string.charAt(a)){
a++;
b--;
}
else {
flag = false;
break;
}
}
if (flag){
test = string.substring(i,j+1);
}
}
if (test.length()>max.length()){
max = test;
}
}
}
return max;
}
第二种解法 暴力解法 (不超时)
在第一中解法中,我们在进行字符比较的时候是取得字符串的下标,这个过程应该是耗时的,我们在的到字符串的时候把字符串转化为char类型的数组,然后操作数组,虽然也是暴力的,但是最后是能够通过的。
if (string.length()<2){
return string;
}
char [] str = string.toCharArray();
int maxi = 0;
int maxj = 0;
for (int i = 0; i < str.length; i++) {
int x = 0;
int y = 0;
for (int j = str.length-1; j >i; j--) {
if (str[i]==str[j]){
int a = i+1;
int b= j-1;
boolean flag=true;
while (b>a){
if (str[b]==str[a]){
a++;
b--;
}
else {
flag = false;
break;
}
}
if (flag){
x = i;
y = j;
}
}
if (y-x>maxj-maxi){
maxi = x;
maxj = y;
}
}
}
return string.substring(maxi, maxj+1);
3、第三种解法 动态规划(操作字符串)
1、定义一个二维数组,来记录两个下标之间是否为回文字串,是的话就为ture,否则false
boolean[][] dp = new boolean[len][len];
2 、如何判断一个字串(如dp[i][j])是否为回文字串的,它有一个条件,就是
string.charAt(i)==string.charAt(j),保证它可能是一个回文子串,其次就是保证它的字串是回文字串,即
dp[left][right]=dp[left+1][right-1];
3、遍历顺序应该是从前往后的
用两个指针,第一个指针从第一个元素开始,第二个指针从第一个元素开始,判断两个指针间的字串是否为回文字串
public static String longestPalindrom2(String string){
int len = string.length();
if (len<=1) return string;
String maxStr = string.substring(0,1);
//两个下标之间的字符串是否为回文串
boolean[][] dp = new boolean[len][len];
//单字符都是回文子串
for (int i = 0; i < len; i++) {
dp[i][i] = true;
}
for (int right = 1;right<len;right++){
for (int left = 0; left <right ; left++) {
if (string.charAt(left) != string.charAt(right)){
dp[left][right] = false;
continue;
}
//两端相等的话
if (left+1>=right-1){
dp[left][right]=true;
}
else {
dp[left][right]=dp[left+1][right-1];
}
if (dp[left][right] && right-left+1>maxStr.length()){
maxStr = string.substring(left,right+1);
}
}
}
return maxStr;
}
4、第四种解法 动态规划(操作char数组)
这个方法是结合了第二种解法和第三种解法的就是把第三种操作字符串改为第二种的操作char数组,这种方式在leetcode的用时是这四种方法中最高的。代码如下:
public static String longestPalindrom4(String string){
int len = string.length();
if (len<=1) return string;
String maxStr = string.substring(0,1);
char[] chars = string.toCharArray();
boolean[][] dp = new boolean[len][len];
//单字符都是回文字串
for (int i = 0; i < len; i++) {
dp[i][i] = true;
}
for (int right = 1;right<len;right++){
for (int left = 0; left <right ; left++) {
if (chars[left] != chars[right]){
dp[left][right] = false;
continue;
}
//两端相等的话
if (left+1>=right-1){
dp[left][right]=true;
}
else {
dp[left][right]=dp[left+1][right-1];
}
if (dp[left][right] && right-left+1>maxStr.length()){
maxStr = string.substring(left,right+1);
}
}
}
return maxStr;
}