字符串的最长回文子串

接着上篇的字符串拆分字符组成回文字符串,这次是不能拆分求最长回文子串。之前在解这个问题的时候,就是硬匹配,还遇到奇偶问题情况,然后看了一点Manacher算法,开始没搞懂,不过用加“#”巧妙解决奇偶情况,最后看懂了,循环的时间复杂度能降到O(n),还是很不错的。
最初的那种分情况讨论的代码就不贴了,贴上加“#”硬匹配的代码和Manacher算法考虑三种情况(i和max比较的两大类)的改进算法。
硬匹配

import java.util.Scanner;

public class Manacher {

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String sInput = sc.nextLine();
        char[] cInput = sInput.toCharArray();
        int n = cInput.length;
        char mp[] = new char[2 * n + 1];// 存储加‘#’的字符数组
        mp[2 * n] = '#';
        int i;
        for (i = 0; i < n; i++) {
            mp[2 * i] = '#';
            mp[2 * i + 1] = cInput[i];
        }
        int p[] = new int[2 * n + 1];// 存储有效回文长度
        p[0] = 0;
        p[2 * n] = 0;
        p[1] = 1;
        p[2 * n - 1] = 1;

        int r;// 左右延展半径
        int d;// 实际延展字符半径
        int maxId = 1;// 存储最长回文字符子串中心
        int maxR = 1;// 存储最长回文字符子串的左右延展半径
        int maxNum = 1;// 存储最长回文字符子串的有效回文长度
        for (i = 2; i < 2 * n - 1; i++) {
            r = 1;
            d = 0;
            while ((i - r >= 0) && (i + r <= 2 * n) && (mp[i - r] == mp[i + r])) {
                if (mp[i - r] != '#')
                    d++;
                r++;
            }
            if (mp[i] == '#')
                p[i] = 2 * d;
            else
                p[i] = 2 * d + 1;

            if (maxNum < p[i]) {
                maxId = i;
                maxR = r - 1;
                maxNum = p[i];
            }
        }

        StringBuffer out = new StringBuffer();
        for (i = maxId - maxR; i < maxId + maxR; i++) {
            if (mp[i] != '#')
                out.append(mp[i]);
        }

        System.out.println("最大回文子串长度:" + maxNum + "\n回文字符串内容为:"
                + out.toString());

    }
}

Manacher改进后

import java.util.Scanner;

public class Manacher {
    public static void main(String[] args) {

        Scanner sc = new Scanner(System.in);
        String sInput = sc.nextLine();
        char[] cInput = sInput.toCharArray();
        int n = cInput.length;
        char mp[] = new char[2 * n + 1];// 存储加‘#’的字符数组
        mp[2 * n] = '#';
        int i;
        for (i = 0; i < n; i++) {
            mp[2 * i] = '#';
            mp[2 * i + 1] = cInput[i];
        }

        int p[] = new int[2 * n + 1];// 存储延展长度
        p[0] = 1;
        p[2 * n] = 1;

        int id = 0;
        int max = 0;

        int maxl = 0;// 存储p[]中最大值
        int maxid = 0;// 存储p[]中最大值的位置

        for (i = 1; i < 2 * n; i++) {// 更新p[]数组
            if (i < max) {
                p[i] = Math.min(p[2 * id - i], max - i);
            } else {
                p[i] = 1;
            }
            while ((i - p[i] >= 0) && (i + p[i] < 2 * n + 1)
                    && (mp[i - p[i]] == mp[i + p[i]])) {
                p[i]++;
            }
            if (i + p[i] > max) {
                max = i + p[i];
                id = i;
            }
            if (maxl < p[i]) {
                maxl = p[i];
                maxid = i;
            }
        }

        // p[i]延展长度包括i本身,所以实际半径需要减一
        // 实际半径其实也是回文串在原字符串中的长度
        int r = maxl - 1;

        StringBuffer out = new StringBuffer();
        for (i = maxid - r; i < maxid + r; i++) {
            if (mp[i] != '#') {
                out.append(mp[i]);
            }
        }

        System.out.println("最大回文子串长度:" + (maxl - 1) + "\n回文字符串内容为:"
                + out.toString());
    }

}

仅供参考,多多交流。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值