• 5.最长回文子串(马拉车怨种版)


    给你一个字符串 s,找到 s 中最长的回文子串。

    示例 1:

    输入:s = "babad"
    输出:"bab"
    解释:"aba" 同样是符合题意的答案。
    示例 2:

    输入:s = "cbbd"
    输出:"bb"
     

    提示:

    1 <= s.length <= 1000
    s 仅由数字和英文字母组成

    思路就是马拉车这个算法,对我来说实现的难度主要是在如何用java写,java的string类用的还是不熟练欸。

    首先介绍一下马拉车算法,作为一个比较冷门的字符串处理方法,理解起来难度比好多了。

    首先我们考虑这样一个问题,就是回文子串的长度分为两种, 一种是奇数,一种是偶数。

     如果是奇数的话就是这样的:   ababa

    如果是偶数的话就是这样的:   aabbaa

    但是如果是偶数的话,我们确实不方便处理,因此我们首先考虑如何吧偶数串,转化为奇数串?

    我们的方法是,在收尾添加两个不同的字符,然后每个原有的字符前面后面都加一个#号。

    这样我们的字符串:比如说奇数的aba就变成了¥#a#b#b#a#^

    这样我们的回文字符串就变成了#a#b#b#a#是个奇数

    1. void init()
    2. {
    3. int k = 0;
    4. b[k ++ ] = '$', b[k ++ ] = '#';
    5. for (int i = 0; i < n; i ++ ) b[k ++ ] = a[i], b[k ++ ] = '#';
    6. b[k ++ ] = '^';
    7. n = k;
    8. }

    然后我们需要求一个叫p[i]的数组

    p代表着转化后的字符串的”半径“

    #a#b#b#a#的半径就是#a#b#长度为5, 里面一共有5 - 1个字符, 也就代表着,我们原来的字符串长度为4;

    那么问题来了,我们如何求这个p呢?

    首先我们要明确这样一件事情,p数组对应的字符串是我们插入#后的字符串, p[i] - 1对应的就是该回文子串在原来字符串的长度

    p[i]表示的是以新字符串b[i]为中心的最长回文子串最右字符到b[i]的距离,也包括b[i]

    计算,我们首先要引入两个变量,一个是mid, 一个是mr;

    mid表示最大回文串中心的位置,

    mr = id + p[id], 代表最大回文子串的有边界

    我们要分情况讨论,根据,i和mr的关系来确定。

    第一种是i

    第二种是i>= mr;

    第一种情况由于我们的i已经小于mr了,说明,在我们当前的最大回文子串 p[mid]中,也有一个p[j]==p[i], 而且由于他俩是对称的,所以会导致:i + j == 2 * mid;

    我们就求得j = 2 * mid - i;

    这时候我们就要考虑如何用p[j]去更新p[i]

    i

    我们现在的i距离mr的距离是mr - i;

            如果p[j] > mr - i; 说明 以 j为中心的回文子串, 左边已经超出了 我们当前最大回文子串的左边界,由于这个回文串对称性, 我们可以知道如果让p[i]等于p[j]的话,当前的条件是,p[i]右边超出mr的那一部分也必须是回文串的一部分,但是这一部分又难以预料,我们还没有求,所以说, p[j] > mr - i; 的情况下,p[i]就是等于mr - i;

            但是如果p[j] <= mr - i;说明,当前j 为中心的回文子串,全部都在最大回文串的内部,对称性可知,这时候的p[i] == p[j];

    再去处理i>= mr;的情况

    由于我们i已经大于mr了,外边的都没有匹配到p[mid]里面去,我们只能暂时让p[i]等于一

    1. if (i < mr) {
    2. p[i] = min(p[mid * 2 - i], mr - i);
    3. } else p[i] = 1;

    最后我们为了解决 i < mr && p[i] > mr - i;和 i >= mr 的情况,我们只能采取向两边拓展的方式:

    while (b[i - p[i]] == b[i + p[i]]) p[i] ++;

    最后更新mr和mid;

    如果i + p[i] > mr, 说明说明以i为中心的回文字串超过的边界mr, 就需要更新

    1. if (i + p[i] > mr) {
    2. mr = i + p[i];
    3. mid = i;
    4. }

     最后是总结一下java用到的函数:

    String的charAt

    Math.min();

    s.substring();

    ok跑路,写了好久这篇哈哈哈

    1. class Solution {
    2. public String longestPalindrome(String s) {
    3. int n = s.length();
    4. char[] a = new char[n * 2 + 1 + 3];
    5. int[] p = new int[n * 2 + 1 + 3];
    6. int k = 0;
    7. a[k ++] = '$';
    8. a[k ++] = '#';
    9. for (int i1 = 0; i1 < n; i1 ++) {
    10. a[k ++] = s.charAt(i1);
    11. a[k ++] = '#';
    12. }
    13. a[k ++] = '^';
    14. n = k;
    15. int mr = 0;
    16. int mid = 0;
    17. for (int i = 1; i < k; i ++) {
    18. if (i < mr) p[i] = Math.min(p[mid * 2 - i], mr - i);
    19. else p[i] = 1;
    20. while (a[i - p[i]] == a[i + p[i]]) p[i] ++;
    21. if (i + p[i] > mr) {
    22. mr = i + p[i];
    23. mid = i;
    24. }
    25. }
    26. int ans = 0;
    27. int res = 0;
    28. for (int i = 0; i < n ; i ++) {
    29. if (res < p[i]) {
    30. ans = i;
    31. res = p[i];
    32. }
    33. }
    34. res --;
    35. if (ans % 2 == 1) { // 是成双成对的
    36. ans = ans / 2 - 1; // 得到的是在子串中,中间偏左的下标
    37. return s.substring(ans - (res / 2) + 1, ans + (res / 2) + 1);
    38. } else {
    39. ans = ans / 2 - 1;
    40. return s.substring(ans - (res / 2), ans + (res / 2) + 1);
    41. }
    42. //System.out.println(res);
    43. //eturn " ";
    44. }
    45. }

  • 相关阅读:
    Centos 8 安装 nginx
    第22节-PhotoShop基础课程-模糊工具
    [Qt基础内容-08] Qt中MVC的M(Model)
    【单片机毕业设计】【mcuclub-hj-013】基于单片机的大棚环境检测的设计
    配电房智能化改造
    Git通过rebase合并多个commit
    VBA处理数据与Python Pandas处理数据案例比较分析
    python easygui怎么修改默认按钮名字
    排序算法的稳定性
    【Python数据分析工具】
  • 原文地址:https://blog.csdn.net/beloved_yu/article/details/127417588