首页 > 试题广场 >

最长回文子串

[编程题]最长回文子串
  • 热度指数:185391 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32M,其他语言64M
  • 算法知识视频讲解
\hspace{15pt}对于给定的由小写字母构成的字符串 s,求出其最长回文子串的长度。

\hspace{15pt}子串为从原字符串中,连续的选择一段字符(可以全选、可以不选)得到的新字符串。
\hspace{15pt}一个字符串被称作回文串,当且仅当这个字符串从左往右读和从右往左读是相同的。

输入描述:
\hspace{15pt}在一行上输入一个长度为 1 \leqq {\rm len}(s) \leqq 350、仅由小写字母构成的字符串 s


输出描述:
\hspace{15pt}输出一个整数,表示字符串 s 的最长回文子串的长度。
示例1

输入

cdabbacc

输出

4

说明

\hspace{15pt}在这个样例中,\texttt{ 是最长的回文子串。
示例2

输入

a

输出

1
import java.util.Scanner;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        // 注意 hasNext 和 hasNextLine 的区别
        while (in.hasNextLine()) { // 注意 while 处理多个 case
            String s = in.nextLine();
            int max = 1;
            for (int i = 1 ; i <= s.length();i++){//子串长度
                for (int j = 0;j <= s.length()-i;j++){//从第几位开始
                    String temp = s.substring(j,j+i);
                    if (isCallBack(temp) && temp.length() > max){
                        max = temp.length();
                    }
                }
            }
            System.out.println(max );
        }
    }
    //判断是否为回子串
    public static boolean isCallBack(String s){
        int length = s.length();
        if ( length == 1){
            return true;
        }
        boolean result = false;
        StringBuilder sb1 = new StringBuilder();
        String s1,s2;
        if (length % 2 == 0){
            s1 = s.substring(0,length/2);
            s2 = s.substring(length/2);
        } else {
            s1 = s.substring(0,length/2);
            s2 = s.substring(length/2 + 1);
        }
        sb1.append(s2);
        String s3 = sb1.reverse().toString();
        if (s3.equals(s1)){
            result = true;
        }
        return result;
    }
}

发表于 2025-09-14 22:09:03 回复(0)
import java.util.Scanner;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        // 注意 hasNext 和 hasNextLine 的区别
        String s = in.next();
        int start = 0, end = 0;

        for (int i = 0; i < s.length(); i++) {
            //奇数长度回文数
            int i1 = huiWenShu(s, i, i);
            //偶数长度回文数
            int i2 = huiWenShu(s, i, i + 1);
            //判断最长的回文子串的长度
            int i3 = Math.max(i1, i2);
            // 如果找到更长的回文,更新起始和结束位置
            if (i3 > end - start) {
                start = i - (i3 - 1) / 2;
                end = i + i3 / 2;
            }
        }

        System.out.println(s.substring(start, end + 1).length() );
    }

    //从中心开始往外扩散获取取回文子串的长度
    public static int huiWenShu(String s, int left, int right) {
        while (left >= 0 && right < s.length() && s.charAt(left) == s.charAt(right)) {
            left--;
            right++;
        }
        return right - left - 1;
    }
}
发表于 2025-08-19 21:10:03 回复(0)
动态规划,子序列系列经典问题,dp[j][i]含义为:j~i范围内是否为回文子串,初始化dp[i][i]为true,表示单个字符一定是回文的。
初始化res = 1,因为回文子串至少为单个字符,递推公式为两层for循环,外层是右指针,内层是左指针。
右指针从i = 1遍历(因为第一个字符i = 0已经为回文了,所以不需要判断),左指针从j = 0~i(不包含i)遍历,若chars[i] = chars[j],继续判断两者间隔,
若两者间隔小于1,即区间内只有三个字符。直接得出区间内是回文子串,结果res = Math.max(max, i - j + 1),若区间内不止三个字符,需要继续判断dp[j + 1][i - 1]是否为回文子串,
如果是。dp[j][i] = true,res = Math.max(res, i - j + 1)。遍历结束后返回res即可
import java.util.Scanner;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        // 注意 hasNext 和 hasNextLine 的区别
        while (in.hasNextLine()) { // 注意 while 处理多个 case
            char[] chars = in.nextLine().toCharArray();
            boolean[][] dp = new boolean[chars.length][chars.length];
            for (int i = 0; i < chars.length; i++){
                dp[i][i] = true;
            }
            int res = 1;
            for (int i = 1; i < chars.length; i++){
                for (int j = 0; j < i; j++){
                    if (chars[i] == chars[j]){
                        if (i - j > 1){
                            if (dp[j + 1][i - 1] == true){
                                dp[j][i] = true;
                                res = Math.max(res, i - j + 1);
                            }
                        }else{
                            dp[j][i] = true;
                            res = Math.max(res, 2);
                        }
                    }
                }
            }
            System.out.println(res);
        }
    }
}

发表于 2025-07-22 10:04:48 回复(0)
import java.util.Scanner;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        // 注意 hasNext 和 hasNextLine 的区别
        while (in.hasNextLine()) { // 注意 while 处理多个 case
            String s = in.nextLine();
            System.out.println(longestPalindrome(s));
        }
    }

    private static int longestPalindrome(String s) {
        if (s == null || s.length() == 0) {
            return 0;
        }

        int max = 0;
        for (int i = 0; i < s.length(); i++) {
            // 以当前字符为中心扩展(奇数长度)
            int len1 = expand(s, i, i);
            // 以当前字符和下一个字符为中心扩展(偶数长度)
            int len2 = expand(s, i, i+1);
            int longer = Math.max(len1, len2);
            max = Math.max(max, longer);
        }
        return max;
    }

    private static int expand(String s, int left, int right) {
        while (left >= 0 && right < s.length() && s.charAt(left) == s.charAt(right)) {
            left--;
            right++;
        }
        return right - left - 1;
    }
}

发表于 2025-02-06 13:11:00 回复(0)
String sb = s.substring(i, i + d);
if (sb.equals(new StringBuilder(sb).reverse().toString())) {  // 回文子串:子串 = 子串反转
    System.out.print(d);
    return;
}

发表于 2025-01-28 19:51:46 回复(0)
import java.util.Scanner;
import java.util.ArrayList;
import java.util.Collections;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        while (sc.hasNext()) {
            String str = sc.next();
            ArrayList<Integer> arr = new ArrayList<>();
            if (str.length() % 2 == 0) {
                for (int mid = 1; mid <= str.length() - 2; mid++) {
                    int count = 0;
                    for (int i = 0 ; i < mid ; i++) {
                        if (str.charAt(mid - i - 1) == str.charAt(mid + i)) {
                            count++;
                        } else {
                            break;
                        }
                    }
                    arr.add(count);
                }
                System.out.println(2 * Collections.max(arr));
            }
            if (str.length() % 2 == 1) {
                for (int mid = 1; mid < str.length() - 2; mid++) {
                    int count = 0;
                    for (int i = 0 ; i < mid ; i++) {
                        if (str.charAt(mid - i - 1) == str.charAt(mid + i + 1)) {
                            count++;
                        } else {
                            break;
                        }
                    }
                    arr.add(count);
                }
                System.out.println(2 * Collections.max(arr) + 1);
            }
        }
    }
}

发表于 2024-10-29 17:20:35 回复(0)

import java.util.Scanner;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        String string = in.nextLine();

        // 遍历每个字符串
        int maxLen = 0;
        String loopWords = "";
        for(int i = 0; i < string.length(); i++) {
            for(int j = i + 1; j < string.length(); j++) {
                String subString = string.substring(i, j);
                int end = j + subString.length();
                if(end > string.length()) {
                    break;
                }
                String theOtherString = string.substring(j, end);
                String reversedString = new StringBuilder(theOtherString).reverse().toString();
                int loopWordsLen = 2 * subString.length();
                if(subString.equals(reversedString) && loopWordsLen > maxLen) {
                    maxLen = loopWordsLen;
                    loopWords = subString + theOtherString;
                }
            }

            for(int j = 1; j <= i; j++) {
                int left = i - j;
                int right = i + 1 + j;
                if(left < 0 || right > string.length()) {
                    break;
                }

                // abcbaaa
                // i = 2, j = 1:  left = 1 right = 4 ls = 1,2 = b, rs = 3,4 = b
                // i = 2, j = 2:  left = 0 right = 5 ls = 0,2 = ab, rs = 3,5 = ba
                // i = 2, j = 3: break;
                String leftStr = string.substring(left, i);
                String rightStr = string.substring(i + 1, right);
                String reversedRightStr = new StringBuilder(rightStr).reverse().toString();
              
                if(!leftStr.equals(reversedRightStr)) {
                    break;
                }

                int loopWordsLen = 2 * leftStr.length() + 1;
                if(loopWordsLen > maxLen) {
                    maxLen = loopWordsLen;
                    loopWords = leftStr + string.substring(i, i+1) + rightStr;
                }
            }
        }

        System.out.println(maxLen);
    }
}

发表于 2024-07-24 18:40:21 回复(0)
双指针中心扩散法
import java.util.*;

public class Main {
    private static int m;
    private static int n;
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        while (in.hasNext()) {
            String line = in.nextLine();
            char[] chars = line.toCharArray();
            int maxLength = 1;
            int left = 0, right = 0;
            int n = 0;
            while (right < chars.length) {
                int length = right - left - 1;
                int start = left, end = right;
                while (start >= 0 && end < chars.length && chars[start] == chars[end]) {
                    start--;
                    end++;
                    length += 2;
                }
                maxLength = Math.max(maxLength, length);
                if (n % 2 == 0) {
                    right++;
                }else {
                    left++;
                }
                n++;
            }
            System.out.println(maxLength);
        }
    }
}
动态规划有两种解法
一种是直接解,dp数组的两个维度分别是子串起点和终点,状态转移公式是:dp[i][j]=dp[i+1][j-1]+2;
另一种就是将先将字符串翻转,题目转化为原字符串和翻转后的字符串最长公共连续子串,这题目就是经典题了,想必大家学dp时都有做过。
发表于 2024-07-03 12:39:36 回复(0)
import java.util.Scanner;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String line = br.readLine();

        int maxLen = 0;
        for (int i = 0; i < line.length(); i++) {
            for (int j = i + 1; j <= line.length(); j++) {
                // 回文字符串 反转后与其自身相等
                String sub = line.substring(i, j);
                StringBuilder sb = new StringBuilder(sub);
                if (sub.equals(sb.reverse().toString()) && sub.length() > maxLen) {
                    maxLen = sub.length();
                }
            }
        }

        System.out.println(maxLen);
    }
}

发表于 2023-08-13 15:58:56 回复(0)
和HJ32 密码截取一模一样,直接粘过来
import java.util.*;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        // 使用双指针法,从中心点到两边扩散,注意有两种星形式的回文子串
        String str = in.nextLine();
        // 定义左右指针
        int l;
        int r;
        // 定义集合接收回文字符的长度
        ArrayList<Integer> list = new ArrayList<>();
        for (int i = 0; i < str.length() - 2; i++) {
            // ABBA型
            int len1 = 0;
            if (str.charAt(i) == str.charAt(i + 1)) {
                // 两边发散继续寻找
                l = i;
                r = i + 1;
                do {
                    len1 += 2;
                    l--;
                    r++;
                } while (r < str.length() && str.charAt(l) == str.charAt(r));
            }
            // ABA型 不是加2 初始值是1
            int len2 = 1;
            if (str.charAt(i) == str.charAt(i + 2)) {
                // 两边发散继续寻找
                l = i;
                r = i + 2;
                do {
                    len2 += 2;
                    l--;
                    r++;
                    //防止数组越界异常前置判断
                } while (l >= 0 && r < str.length() && str.charAt(l) == str.charAt(r));
            }
            list.add(Math.max(len1, len2));
        }
        System.out.println(Collections.max(list));

    }
}

发表于 2023-06-30 21:09:23 回复(1)
import java.util.Scanner;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        // 注意 hasNext 和 hasNextLine 的区别
         String str=in.nextLine();
         int len=str.length();
         if(len<1||len>350)
         return;
         int count1=0,count2=0;
         int pos1=0,pos2=1;
         for(int i=1;i<len-1;i++)
         {
           
            pos2=i;pos1=i-1;
            if(str.charAt(i-1)==str.charAt((i)))
            {
                pos1=i-1;pos2=i;
            }
            else if(str.charAt(i-1)==str.charAt((i+1)))
            {
                pos1=i-1;pos2=i+1;
            }
            while(str.charAt(pos1)==str.charAt(pos2))
            {
                count2=pos2-pos1+1;
                pos1--;pos2++;
                if(pos1<0||pos2>=len)
                break;
            }
            if(count2>count1)
            count1=count2;
            count2=0;  
         }
         System.out.println(count1);
    }
}
//瞎写
发表于 2023-06-28 22:45:51 回复(0)
import java.util.Scanner;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        String a = in.nextLine();
        int max = 0;
        for (int i = 0; i < a.length(); i++) {
            for (int j = i+1; j <= a.length(); j++) {
               String sub = a.substring(i,j);
               if (isPalindrome(sub) && sub.length() > max){
                   max = sub.length();
               }
            }
        }
        System.out.println(max);
    }
    private static boolean isPalindrome(String str){
       StringBuilder sub = new StringBuilder(str).reverse();
       if (str.equals(sub.toString())){
           return true;
       }
       return false;
    }
 }   

发表于 2023-06-07 14:30:46 回复(0)
回文长度
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        String line = in.nextLine();

        int num = 1; // 默认回文最小长度为1(单个字符)
        for (int i = 0; i < line.length(); i++) {
            // 回文长度为偶数
            int k = Math.min(i + 1, line.length() - i - 1);
            int idx = 0;
            while (k > idx) {
                if (line.charAt(i - idx) != line.charAt(i + 1 + idx)) {
                    break;
                }
                idx++;
            }
            num = Math.max(num, 2 * idx);

            // 回文长度为奇数
            k = Math.min(i, line.length() - i - 1);
            idx = 0;
            while (k > idx) {
                if (line.charAt(i - 1 - idx) != line.charAt(i + 1 + idx)) {
                    break;
                }
                idx++;
            }
            num = Math.max(num, 2 * idx + 1);
        }
        System.out.println(num);
    }
}

发表于 2023-05-14 18:29:39 回复(0)
 public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        // 注意 hasNext 和 hasNextLine 的区别
        while (in.hasNext()) { // 注意 while 处理多个 case
            String a = in.next();
            TreeMap<Integer,String> treeMap = new TreeMap<Integer,String>();
            for(int i=0;i<a.length();i++){
                for(int j=a.length();j>i;j--){
                    StringBuffer bf = new StringBuffer();
                    String substr = a.substring(i,j);
                    bf.append(substr);
                    String reverse = bf.reverse().toString();
                    if(substr.endsWith(reverse)){
                        treeMap.put(substr.length(),substr);
                    }
                }
            }
            System.out.println(treeMap.lastEntry().getKey());
        }
    }
发表于 2023-04-19 19:30:23 回复(0)
import java.util.*;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static int[] p1=new int[400];
    public static int[] p2=new int[400];
    public static int[] p3=new int[400];
    public static int[] dp=new int[400];
    public static boolean check(int x,int y){
        int a=p2[y]-p2[x-1]*p1[y-x+1];
        int b=p3[x]-p3[y+1]*p1[y-x+1];
        return a==b;
    }
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        // 注意 hasNext 和 hasNextLine 的区别
        while (in.hasNext()) { // 注意 while 处理多个 case
            Arrays.fill(p2,0);
            Arrays.fill(p3,0);
            Arrays.fill(dp,0);
            String s=in.next();
            int n=s.length(),ans=0;
            p1[0]=1;
            for(int i=1;i<=n;i++){
                dp[i]=1;
                p1[i]=p1[i-1]*27;
                p2[i]=p2[i-1]*27+(s.charAt(i-1)-'a');
                p3[n-i+1]=p3[n-i+2]*27+(s.charAt(n-i)-'a');
            }
            for(int i=1;i<=n;i++){
                if(i-dp[i-1]>0&&check(i-dp[i-1],i)) dp[i]=Math.max(dp[i-1]+1,dp[i]);
                if(i-1-dp[i-1]>0&&check(i-1-dp[i-1],i)) dp[i]=Math.max(dp[i-1]+2,dp[i]);
                ans=Math.max(ans,dp[i]);
            }
            System.out.println(ans);
        }
    }
}

发表于 2023-04-09 20:10:54 回复(0)
/**
 * ☆☆☆☆☆
 * 最长回文子串
 * 中心扩展 + 动态规划 + Manacher
 */
private static void longestPalindrome2() {
    Scanner in = new Scanner(System.in);
    while (in.hasNext()) {
        String s = in.nextLine();
        // 字符间隔及两边插入#,方便统一中心扩展方式的两种情况:中心在元素上和中心在元素间
        StringBuilder sb = new StringBuilder("#");
        for (int i = 0; i < s.length(); i++) {
            sb.append(s.charAt(i)).append("#");
        }
        // 数组用于存插入#后,当前元素为中心的最大回文半径(自身算1)
        // 最终的最大回文长度是该半径-1(该半径多出来的#,比另一边的原字符多一)
        int[] arr = new int[sb.length()];
        // 已知的所有回文串的最右边界+1
        int maxPos = 0;
        // 边界最右的回文串的中心
        int index = 0;
        for (int i = 0; i < sb.length(); i++) {
            if (i < maxPos) {
                // 此处是关键,i相对index的对称位置2*index-i,直接参与计算,避免重复计算
                arr[i] = Math.min(arr[2 * index - i], maxPos - i);
            } else {
                arr[i] = 1;
            }
            // 在已有基础上继续扩展判断,越界判断,以及两边字符判断
            while (i - arr[i] >= 0 && i + arr[i] < sb.length() && sb.charAt(i - arr[i]) == sb.charAt(i + arr[i])) {
                arr[i]++;
            }
            // 更新maxpos和index
            if (i + arr[i] > maxPos) {
                maxPos = i + arr[i];
                index = i;
            }
        }
        int max = 0;
        for (int i = 0; i < sb.length(); i++) {
            max = Math.max(max, arr[i]);
        }
        // 最长回文串的长度
        System.out.println(max - 1);
        // 最长回文串
        for (int i = 0; i < sb.length(); i++) {
            if (max == arr[i]) {
                String result = sb.substring(i - arr[i] + 1, i + arr[i]).replace("#", "");
                System.out.println(result);
                break;
            }
        }
    }
}

发表于 2023-03-25 20:07:06 回复(0)
动态规划
import java.util.Scanner;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        // 注意 hasNext 和 hasNextLine 的区别
        while (in.hasNext()) { // 注意 while 处理多个 case
            String str = in.nextLine();
            // dp[i][j]数组, 标记下标i-j是否为回文串,
            // 1. 单个字符肯定是回文串, dp[i][i] == true
            // 2. 如果i~j是回文子串,那么i+1~j-1肯定也是回文子串
            String subStr = getMaxLongStr(str);
            System.out.println(subStr.length());
        }
    }

    private static String getMaxLongStr(String str) {
        int begin = 0;
        int maxLen = 1;
        int len = str.length();
        char[] arr = str.toCharArray();
        // 定义dp数组
        // 单个字符都是回文
        boolean[][] dp = new boolean[len][len];
        for (int i = 0; i < len; i++) {
            dp[i][i] = true;
        }
        // dp[i][j] 参考的是 dp[i+1][j-1] 
        // 边界条件: (j-1) - (i+1) + 1 < 2,则不需要参考
        // 整理: j - i < 3
        for (int j = 1; j < len; j++) {
            for (int i = 0; i < j; i ++) {
                if (arr[i] != arr[j]) {
                    dp[i][j] = false;
                } else {
                    if (j - i < 3) {
                        dp[i][j] = true;
                    } else {
                        dp[i][j] = dp[i+1][j-1];
                    }
                }
                // 更新最大子串
                if (dp[i][j] && j - i + 1 > maxLen) {
                    begin = i;
                    maxLen = j - i + 1;
                }
            }
        }

        return str.substring(begin, begin+maxLen);
    }
}


发表于 2023-03-16 13:53:09 回复(0)
import java.util.Scanner;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        String s1 = in.nextLine();
        in.close();

        int size = s1.length();
        int res = 1;
        for (int k = 0; k < size; k++) {
            res = Math.max(res, centreExtend(s1, k, k, size));
        }
        for (int k = 0; k < size-1; k++) {
            if (s1.charAt(k) == s1.charAt(k+1)) {
                res = Math.max(res, centreExtend(s1, k, k+1, size));
            }
        }
        System.out.println(res);
    }

    private static int centreExtend(String s1, int i, int j, int size) {
        while (i-1 >= 0 && j+1 < size && s1.charAt(i-1) == s1.charAt(j+1)) {
            i--;
            j++;
        }
        return j - i + 1;
    }
}

发表于 2023-03-02 13:26:50 回复(0)