首页 > 编程语言 >manacher(马拉车)算法C++详解

manacher(马拉车)算法C++详解

时间:2023-08-10 15:46:38浏览次数:47  
标签:int manacher len ++ 详解 C++ max 字符串 回文

马拉车的定义

马拉车本质是对中心扩展法(暴力算法)的优化。

马拉车是干什么的

Manacher算法帮助我们在给定的字符串中找到最长的回文子串
为了简单起见,我们先只处理有奇数个字符的字符串,关于偶数个字符的字符串,在文章最后会给出解法。我们的处理思路和暴力算法基本一致,那就是从左到右一个字符一个字符来处理这个字符串,寻找以当前处理的字符为中心的最长回文串,假设字符串的长度是N,那我们就在寻找到的N个最长回文串中取最长的就是答案了。

符号说明

我们约定,c是我们处理当前字符时,已经找到的右边界最大的回文字符串的中心。l和r分别是这个最长的回文字符串的左界和右界,也就是最左边的字符索引和最右边的字符索引。现在,我们举个例子来理解c、l和r。
例子:“abacabacabb”
image
当从左到右一个字符一个字符计算时,我们用i表示当前正在处理的字符的索引,当i在索引1时,最长的回文字符串是 "aba"(长度=3)。
当i在索引5时,如下图所示:
image
最长的回文字符串的答案是9,c、l、r的值如图中所示。
不难看出,c所代表的最长回文字符串
现在我们知道了c、l和r表示什么,为了下面算法的讲解更加自然,我们需要了解一个概念:镜像索引。
对于以c为中心的任何一个回文字符串来说 索引j关于c的镜像是j',如下图所示:
image
观察上图,不难得出下面的计算公式:

c - j = j' - c

此时,j的镜像j':

j' = (2 * c) - j

模板

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int maxn = 3e5 + 5;
char s[maxn], t[maxn];
int p[maxn];

int main() {
    while (~scanf("%s", s)) {
        int l = strlen(s), len = 0;
        t[len++] = '$'; // 在字符串开头和结尾都添加一个特殊字符(如'$',
                        // 注意不要相同),使后续计算可以避免判断越界
        t[len++] = '#';
        for (int i = 0; i < l; ++i) {
            t[len++] = s[i];
            t[len++] = '#';
        }
        t[len] = '&';

        int center = 0, max_right = 0;
        for (int i = 1; i < len; ++i) {
            int i_mirror = 2 * center - i;
            if (max_right >
                i) { // 在最右边界的覆盖范围内, 就利用回文串特征计算长度
                p[i] = min(max_right - i,
                           p[i_mirror]); // 使用min()是为了防止超出最右边界
            } else {
                p[i] = 0;
            }
            while (t[i - 1 - p[i]] == t[i + 1 + p[i]])
                ++p[i];

            if (i + p[i] > max_right) { // 更新右边界的回文串中心
                center = i;
                max_right = i + p[i];
            }
        }

        int max_len = 0;
        // int pos = 0;  //记录最长回文子串中心的位置
        for (int i = 1; i < len; ++i)
            if (max_len < p[i]) {
                max_len = p[i];
                // pos = i;
            }
        printf("%d\n", max_len); //最长回文串的起始位置为: (pos - max_len) / 2
    }
    return 0;
}

标签:int,manacher,len,++,详解,C++,max,字符串,回文
From: https://www.cnblogs.com/ypzmlmf/p/manacher.html

相关文章

  • 详解ConfuserEx的Anti Tamper与Anti Dump
    title:详解ConfuserEx的AntiTamper与AntiDumpdate:2018-08-14updated:2023-04-11lang:zh-CNcategories:-[.NET逆向]tags:-.NET-逆向工程-脱壳-ConfuserEx-反篡改-反转储toc:true文章首发于https://wwh1004.github.io/inside-confuserex-antitamper-......
  • 详解ILProtector并写出脱壳机
    title:详解ILProtector并写出脱壳机date:2018-11-18updated:2023-04-09lang:zh-CNcategories:-[.NET逆向]tags:-.NET-逆向工程-脱壳-ILProtectortoc:true文章首发于https://wwh1004.github.io/inside-ilprotector-and-writing-an-unpacker/ILProtector的......
  • C/C++基础知识点
    C和C++的区别C++是C的超集,C是面向过程化的结构性语言,而C++是面向对象的编程语言C语言更偏向于底层,使用较为灵活,可移植性强,而C++更偏向于上层,可扩展性强,对于大型项目往往使用C++C++在C语言的基础上提出了STL标准模板库,函数模板等特性static关键字的作用隐藏,凡事变量前添加s......
  • c++枚举详细介绍以及具体用法
    C++中的枚举(Enumeration)是一种用于定义命名常量集合的数据类型。枚举可以提高代码的可读性和可维护性,让您可以使用有意义的名称来表示特定的取值,而不必使用原始的数字常量。枚举的基本语法:enumEnumName{Value1,Value2,//...};EnumName是枚举类型的名称......
  • C/C++开发者必备 如何获取系统环境变量的方法
    获取系统环境变量在C/C++中是一项简单的任务。下面展示了一个纯C语言实现的方法。```c#include<stdio.h>#include<stdlib.h>intmain(void){char*pathVar;pathVar=getenv("PATH");printf("pathVar=%s",pathVar);return0;}```需要注意的是,`getenv()`函数定义......
  • 我的第一篇博客--C++课程设计
    目录前言一、题目1.数位之和2.数字排序3.字符串匹配二、问题分析1.数位之和2.数字排序3.字符串匹配三、具体代码1.数位之和2.数字排序3.字符串匹配总结前言这是我的第一篇博客,内容便是最近所做的课程设计,之后也会每天和大家分享一下刷题笔记,以及AC后的代码,希望大家的批评指正,分享大......
  • 详解UART、USART、SPI、IIC、CAN,以太网等通信协议
    目录详解UART、USART、SPI、IIC、CAN,以太网等通信协议基本通信知识通信协议分类串行和并行同步和异步全双工和半双工波特率UARTUSARTSPIIICCAN以太网详解UART、USART、SPI、IIC、CAN,以太网等通信协议基本通信知识通信协议分类串行和并行串行通信是指利用一条传输线将数据一......
  • BigDecimal 详解
    《阿里巴巴Java开发手册》中提到:“为了避免精度丢失,可以使用BigDecimal来进行浮点数的运算”。浮点数的运算竟然还会有精度丢失的风险吗?确实会!示例代码:floata=2.0f-1.9f;floatb=1.8f-1.7f;System.out.println(a);//0.100000024System.out.println(b);//0.0......
  • Linux基础概念:历史、发展、发行版及命令行工具详解
    ·介绍:Linux是一种开源的、类Unix操作系统内核,它具有广泛的应用领域和强大的稳定性。本文将深入探讨Linux的历史与发展、常见的Linux发行版及其特点,以及常用的Linux命令行工具和基本操作。此外,还会提供个人见解和难点解析。一、Linux的历史与发展Linux的历史可以追溯到1991年,由芬......
  • 【Linux】进程优先级 | 进程的切换 | 环境变量详解
      ......