前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >LeetCode647. 回文子串

LeetCode647. 回文子串

作者头像
MashiroT
发布2023-03-14 17:54:25
1400
发布2023-03-14 17:54:25
举报
文章被收录于专栏:MashiroのBlog

LeetCode647. 回文子串

给你一个字符串 s ,请你统计并返回这个字符串中 回文子串 的数目。 回文字符串 是正着读和倒过来读一样的字符串。 子字符串 是字符串中的由连续字符组成的一个序列。 具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被视作不同的子串。

示例1

代码语言:javascript
复制
输入:s = "abc"
输出:3
解释:三个回文子串: "a", "b", "c"

示例2

代码语言:javascript
复制
输入:s = "aaa"
输出:6
解释:6个回文子串: "a", "a", "a", "aa", "aa", "aaa"

Manacher 算法

代码语言:javascript
复制
/**
     * Manacher
     */
    public int countSubstrings(String s) {
        int len = s.length();
        StringBuilder sb = new StringBuilder("$#");
//        解决回文串奇数长度和偶数长度的问题,处理方式是在所有的相邻字符中间插入 '#' ,这样可以保证所有找到的回文串都是奇数长度的
        for (int i = 0; i < len; ++i) {
            sb.append(s.charAt(i)).append('#');
        }
//        设置哨兵,到了边界就一定会不相等,从而结束循环
        sb.append('%');
        len = sb.length();
//        用 radius[i] 来表示以 sb 的第 i 位为回文中心,可以拓展出的最大回文半径
        int[] radius = new int[len];
//        维护 当前最靠右的回文右端点 maxRight , 以及这个回文右端点对应的回文中心 maxMid
        int maxMid = 0;
        int maxRight = 0;
        int rs = 0;
//        剪枝
        for (int currMid = 2; currMid < len - 2; currMid++) {
//            radius[currMid] = [maxRight - currMid, radius[currMid 关于 maxMid 对称点]]
//            currMid 在当前最大回文子串内:
//              回文串的性质,关于回文中心对称的两边一样,因此当前点的回文半径至少是对称点的回文半径
//              因此 currMid 处的 回文半径 最小为 对称点的最大回文半径
//                特殊情况:currMid + 对称点的最大回文半径 > maxRight
//                此时无法取到整个对称点的最大回文半径 , 但最小可以是 currMid 到 maxRight 之间
//            currMid 不在当前最靠右的回文串内:
//              以 currMid 为中心 1 为回文半径
            radius[currMid] = currMid <= maxRight ? Math.min(maxRight - currMid + 1, radius[2 * maxMid - currMid]) : 1;
//            中心拓展
            while (sb.charAt(currMid + radius[currMid]) == sb.charAt(currMid - radius[currMid])) {
                radius[currMid]++;
            }
//            动态维护 maxMid 和 maxRight
//            当前回文右端点 = 当前中心 + 最大回文半径 - 1 > 最大回文右端点
            if (currMid + radius[currMid] - 1 > maxRight) {
                maxMid = currMid;
                maxRight = currMid + radius[currMid] - 1;
            }
//            最长回文子串的结尾一定是 '#' , 因为如果结尾是有实际意义的字符,其两端一定都是 '#'
//            中心位置如果是 '#' 则半径为偶数
//            # a # b [#] b # a #   此时回文半径为 4 , 4 >> 1 == 2
//            如果为实际意义的字符则半径为奇数向下取整
//            # a # b # [currMid] # b # a #   此时回文半径为 5 , 5 >> 1 == 2
            rs += radius[currMid] >> 1;
        }
        return rs;
    }

中心扩散

代码语言:javascript
复制
/**
     * 中心扩散
     */
    public int countSubstrings2(String s) {
        int rs = 0;
        int len = s.length();
//        对于一个长度为n的字符串,可以用它的任意一个字符当做中心点,所以中心点的个数是n。
//        还可以用它任意挨着的两个字符当做中心点,所以中心点是n-1,总的中心点就是2*n-1。
        for (int mid = 0; mid < (len << 1) - 1; mid++) {
            int left = mid >> 1;
            int right = left + (mid & 1);
            while (left >= 0 && right < len && s.charAt(left) == s.charAt(right)) {
                rs++;
                left--;
                right++;
            }
        }
        return rs;
    }

    public int countSubstrings3(String s) {
        int rs = 0;
        int len = s.length();
        for (int mid = 0; mid < len; mid++) {
            int left = mid;
            int right = mid;
            while (left >= 0 && right < len && s.charAt(left) == s.charAt(right)) {
                rs++;
                left--;
                right++;
            }
        }
        for (int mid = 0; mid < len; mid++) {
            int left = mid;
            int right = mid + 1;
            while (left >= 0 && right < len && s.charAt(left) == s.charAt(right)) {
                rs++;
                left--;
                right++;
            }
        }
        return rs;
    }
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023 年 01 月,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • LeetCode647. 回文子串
    • Manacher 算法
      • 中心扩散
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档