回文子串的最大长度 nlogn

这篇具有很好参考价值的文章主要介绍了回文子串的最大长度 nlogn。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

题目地址
回文子串模板题

题目描述

如果一个字符串正着读和倒着读是一样的,则称它是回文的。

给定一个长度为 N N N 的字符串 S S S,求他的最长回文子串的长度是多少。

输入格式

输入将包含最多 30 30 30 个测试用例,每个测试用例占一行,以最多 1000000 1000000 1000000 个小写字符的形式给出。

输入以一个以字符串 END 开头的行表示输入终止。

输出格式

对于输入中的每个测试用例,输出测试用例编号和最大回文子串的长度(参考样例格式)。

每个输出占一行。

输入样例:
abcbabcbabcba
abacacbaaaab
END
输出样例:
Case 1: 13
Case 2: 6

算法

求一个字符串中的最长回文子串。采用了哈希判断,其基本思想如下:给定一个字符串,为了方便处理,首先将字符串中的每个字符间都插入一个额外的字符(这里是 ‘z’ + 1)。这样做的好处是原来的回文串有奇数长度与偶数长度,加了额外字符之后只存在奇数长度的回文串。 (eg:aba,abba->a#b#a,a#b#b#a, l e n = 2 s + 1 len=2s+1 len=2s+1

然后分别计算字符串从头到尾( h l hl hl)和从尾到头( h r hr hr)的哈希值。接着,通过比较从某个位置 i i i 往两边延伸出去的子串的哈希值,来判断这个子串是否为回文。

判断延伸出去的子串的长度,具有可二分性质,因为在分界点的一侧不满足回文,另一侧满足回文。只要有够区分两侧的性质就可以二分。

具体过程:

  1. 输入一个字符串 s s s,并计算其长度 n n n。在字符串的每个字符间插入一个特殊字符 ‘z’ + 1,得到新的字符串 s ′ s' s。新字符串的长度变为 n : = 2 n n:=2n n:=2n
  2. 计算字符串 s ′ s' s 的哈希值 h l hl hl 和其逆序字符串的哈希值 h r hr hr。这里, h l [ i ] hl[i] hl[i] 表示的是从字符串 s ′ s' s 的开头到第 i i i 个字符的哈希值, h r [ i ] hr[i] hr[i] 表示的是从字符串 s ′ s' s 的末尾到第 i i i 个字符的哈希值。
  3. 对于每个合法的位置 i i i,采用二分的方式找到以 i i i 为中心的最长回文子串。首先设定搜索的范围为 [ 0 , min ⁡ ( i − 1 , n − i ) ] [0, \min(i - 1, n - i)] [0,min(i1,ni)],然后在这个范围内进行二分搜索。假设当前的搜索位置为 m i d mid mid,则需要比较从 i − m i d i - mid imid i − 1 i - 1 i1 的哈希值 g e t ( h l , i − m i d , i − 1 ) get(hl, i - mid, i - 1) get(hl,imid,i1) 与从 n − ( i + m i d ) + 1 n - (i + mid) + 1 n(i+mid)+1 n − ( i + 1 ) + 1 n - (i + 1) + 1 n(i+1)+1 的哈希值 g e t ( h r , n − ( i + m i d ) + 1 , n − ( i + 1 ) + 1 ) get(hr, n - (i + mid) + 1, n - (i + 1) + 1) get(hr,n(i+mid)+1,n(i+1)+1) 是否相等。如果这两个哈希值相等,则意味着以 i i i 为中心,长度为 m i d mid mid 的子串是回文的,所以可以继续扩大长度搜索;否则,就需要缩小长度。
    1. 关与第二个 n − ( i + m i d ) + 1 n - (i + mid) + 1 n(i+mid)+1 n − ( i + 1 ) + 1 n - (i + 1) + 1 n(i+1)+1 的计算,原理是一个字符在 h l hl hl中位置为 x x x,在 h r hr hr中位置为 n − x + 1 n-x+1 nx+1,所以 i − m i d i - mid imid i − 1 i - 1 i1 对应于 n − ( i + 1 ) + 1 n - (i + 1) + 1 n(i+1)+1 n − ( i + m i d ) + 1 n - (i + mid) + 1 n(i+mid)+1,同时由于 h l hl hl中靠左的字符在 h r hr hr中会变成靠右,所以顺序交换
  4. 将找到的每个位置 i i i 的最长回文子串的长度记录下来,并在所有位置中找到最大的长度,记为 r e s res res。注意在记录长度时,如果 s ′ [ i − l ] s'[i - l] s[il] (最左端字符)是原来字符串中的字符,那么长度为 l + 1 l + 1 l+1,否则长度为 l l l。这是因为在字符串的每个字符间都插入了一个额外的字符。#a#b#a和a#b#a这两种情况要分别处理
  5. 最后,输出最长回文子串的长度 r e s res res

时间复杂度

在这个过程中,哈希值的计算使用了滚动哈希的方法,即每个位置的哈希值都是基于前一个位置的哈希值计算出来的,这样可以在常数时间内得到任意位置的哈希值。另外,比较两个子串是否相等时,也是通过比较它们的哈希值来实现的。搜索时使用二分。所以整个程序的时间复杂度是 O ( n log ⁡ n ) O(n \log n) O(nlogn),其中 n n n 是字符串的长度。文章来源地址https://www.toymoban.com/news/detail-438312.html

代码

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

typedef unsigned long long ULL;
const int N = 2e6 + 10, base = 13331;

char s[N];
ULL hl[N], hr[N], p[N];

ULL get(ULL h[], int l, int r){
    return h[r] - h[l - 1] * p[r - l + 1];
}
int main()
{
    int T = 1;
    while(scanf("%s", s + 1), strcmp(s + 1, "END"))
    {  // 逗号运算符看最后一项真值
        int n = strlen(s + 1);
        for(int i = 2 * n; i > 0; i -= 2)
        {
            s[i] = s[i / 2];
            s[i - 1] = 'z' + 1;
        }
        n *= 2;
        p[0] = 1;
        for(int i = 1, j = n; i <= n; ++ i, -- j)
        {
            hl[i] = hl[i - 1] * base  + s[i];
            hr[i] = hr[i - 1] * base + s[j];
            p[i] = p[i - 1] * base;
        }
        int res = 0;
        for(int i = 1; i <= n; ++ i)
        {
            int l = 0, r = min(i - 1, n - i);  //  1...i...n
            while(l < r)
            {
                int mid = l + r + 1 >> 1;
                if(get(hl, i - mid, i - 1) != get(hr, n - (i + mid) + 1, n - (i + 1) + 1)) r = mid - 1;
                else l = mid;
            }
            int len = 0;
            if(s[i - l] <= 'z') len = l + 1;
            else len = l;
            res = max(res, len);
        }
        printf("Case %d: %d\n", T ++, res);
    }
    return 0;
}

到了这里,关于回文子串的最大长度 nlogn的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【华为OD统一考试B卷 | 100分】求满足条件的最长子串的长度(C++ Java JavaScript Python)

    在线OJ 已购买本专栏用户,请私信博主开通账号,在线刷题!!! 运行出现 Runtime Error 0Aborted,请忽略 华为OD统一考试A卷+B卷 新题库说明 2023年5月份,华为官方已经将的 2022/0223Q(1/2/3/4)统一修改为OD统一考试(A卷)和OD统一考试(B卷)。 你收到的链接上面会标注A卷还是B卷。

    2024年02月10日
    浏览(32)
  • 【滑动窗口】长度最小的子数组|无重复字符的最长子串|最大连续1的个数 III|将 x 减到 0 的最小操作数

    1. 长度最小的子数组 - 力扣(LeetCode) (1)方法一:暴力列举出所有的子数组的和 时间复杂度:O(n**2):枚举所有子数组O(n**2) (2)方法二: 利用 单调性(两个指针都不回退) ,使用\\\" 同向双指针 \\\"(其实就是 滑动窗口 )来优化 那么 滑动窗口过程 是怎么样的? 1le

    2024年03月22日
    浏览(54)
  • python判断字符串是否包含子串的五种方法

    要判断某一个字符串是否包含某一个子串,方法之一是可以利用python内置的字符串方法find()来查找,如果查找到,就返回子串第一个字符在原字符串中的索引位置,如果找不到,则返回-1,实例代码如下: count()也是python内置的字符串方法之一,可以用于统计参数指定的子串在

    2024年02月11日
    浏览(60)
  • 【动态规划】【记忆化搜索】【回文】1312让字符串成为回文串的最少插入次数

    【动态规划】【字符串】【表达式】2019. 解出数学表达式的学生分数 动态规划汇总 记忆化搜索 回文 字符串 给你一个字符串 s ,每一次操作你都可以在字符串的任意位置插入任意字符。 请你返回让 s 成为回文串的 最少操作次数 。 「回文串」是正读和反读都相同的字符串。

    2024年02月19日
    浏览(52)
  • 动态规划学习——最长回文子序列,让字符串变成回文串的最小插入次数

    1.题目 给你一个字符串  s  ,找出其中最长的回文子序列,并返回该序列的长度。 子序列定义为:不改变剩余字符顺序的情况下,删除某些字符或者不删除任何字符形成的一个序列。 示例 1: 示例 2: 提示: 1 = s.length = 1000 s  仅由小写英文字母组成 2.题目接口  3.解题思路

    2024年02月04日
    浏览(55)
  • 647.回文子串 516.最长回文子序列

    力扣题目链接(opens new window) 给定一个字符串,你的任务是计算这个字符串中有多少个回文子串。 具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被视作不同的子串。 示例 1: 输入:“abc” 输出:3 解释:三个回文子串: “a”, “b”, “c” 示例 2: 输入

    2024年01月19日
    浏览(45)
  • Day 57|647. 回文子串| 516.最长回文子序列

    ● 647. 回文子串 ● 516.最长回文子序列 ● 动态规划总结篇 难

    2024年02月16日
    浏览(47)
  • LeetCode刷题 | 647. 回文子串、516. 最长回文子序列

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

    2024年02月12日
    浏览(49)
  • 算法刷题|647.回文子串、516.最长回文子序列

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

    2024年02月17日
    浏览(51)
  • 最长子串和回文子串相关的算法题解

    中等 给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。 示例 1: 输入: s = “abcabcbb” 输出: 3 解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。 示例 2: 输入: s = “bbbbb” 输出: 1 解释: 因为无重复字符的最长子串是 “b”,所以其长度为 1。 示

    2024年02月19日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包