写法一:

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<vector>
#include<cmath>
#include<string>
#include<map>
#include<queue>
using namespace std;
const int MAXN = 1005;
struct node {int next[26];//指向在当前节点串的基础上左右两边同时添加相同字符后形成的回文串 int len;//此节点串的长度 int sufflink;//此节点的最长后缀回文串的指针 int num;//此节点中的回文子串的个数
};int len;
char s[MAXN];
node tree[MAXN];
int num;            // node 1 - root with len -1, node 2 - root with len 0
int suff;           // max suffix palindrome
long long ans;bool addLetter(int pos) {int cur = suff;//当前以pos-1结尾的最长后缀回文子串的节点标号(即p的长度) int curlen;int let = s[pos] - 'a';//沿着后缀链接边找到满足xAx形式的最长后缀回文子串 while (true) {curlen = tree[cur].len;//当前A的长度 //判断xAx的两个x处的的字母是否都是x if (pos - 1 - curlen >= 0 && s[pos - 1 - curlen] == s[pos])break;cur = tree[cur].sufflink;//沿着后缀链接边找 (节点下标)}//找到xAx后接着找此节点是否存在//注意:节点表示A的next指针指向xAx,每个节点表示的是一个回文串 //xAx即为 以pos下标结尾的最长后缀回文子串的标号if (tree[cur].next[let]) {suff = tree[cur].next[let];//保留当前以pos下标结尾的最长后缀回文子串的标号(已经有的) return false;}//每增加一个节点,num++ num++;suff = num;//保留当前以pos下标结尾的最长后缀回文子串的标号(新增加的)tree[num].len = tree[cur].len + 2;//增加了连个x tree[cur].next[let] = num;// 节点表示A的next指针指向xAx//判断A是都对应长度为-1的根 if (tree[num].len == 1) {tree[num].sufflink=2;//指向长度为0的根 tree[num].num = 1;return true;}//接下来找tree[num].sufflink while (true) {cur = tree[cur].sufflink;curlen = tree[cur].len;if (pos - 1 - curlen >= 0 && s[pos - 1 - curlen] == s[pos]) {tree[num].sufflink=tree[cur].next[let];//tree[cur].next[let]--->xBx break;}}//求num节点中回文串的个数//就是回文串xBx的个数加一(多了一个xAx) tree[num].num = 1 + tree[tree[num].sufflink].num;return true;
}void initTree() {num = 2; suff = 2;tree[1].len = -1; tree[1].sufflink = 1;//长度为-1的根 tree[2].len = 0; tree[2].sufflink = 1;//长度为0的根
}int main() {scanf("%s", s);len = strlen(s);initTree();for (int i = 0; i < len; i++) {addLetter(i);ans += tree[suff].num;//加上每个节点的回文串个数 }cout << ans << endl;return 0;
}

写法二:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define ri register int
using namespace std;const int maxn = 300010;
int n, m, tot, cnt[maxn], len[maxn], fail[maxn], last, son[maxn][27], cur;
char s[maxn];
long long ans;
//添加节点
inline int new_node(ri x)
{//更新len,cnt len[tot] = x; cnt[tot] = 0;return tot++;
}
//找到最长后缀节点
inline int get_fail(ri x, ri n)
{while(s[n-len[x]-1] != s[n]) x = fail[x];return x;
}
//
inline void init()
{scanf("%s", s+1);n = strlen(s+1);//初始化两个根节点 new_node(0); new_node(-1);fail[0] = 1; last = 0;
}int main()
{init();for(ri i=1;i<=n;i++){ri x = s[i] - 'a';cur = get_fail(last, i);//找到最长后缀回文串 if(!son[cur][x]){//没有此回文串 ri nw = new_node(len[cur]+2);fail[nw] = son[get_fail(fail[cur],i)][x];son[cur][x] = nw;}last = son[cur][x];cnt[last]++;}//计算出来的cnt[i]表示i节点回文子串出现的次数 for(int i=tot-1;i>=0;i--) cnt[fail[i]] += cnt[i];for(int i=2;i<tot;i++) {ans+=cnt[i];}cout<<ans<<endl;return 0;
}

求字符串中回文子串的个数(回文树详解)相关推荐

  1. HDU 4622 求解区间字符串中的不同子串的个数

    题目大意: 给定一个长度<2000的串,再给最多可达10000的询问区间,求解区间字符串中的不同子串的个数 这里先考虑求解一整个字符串的所有不同子串的方法 对于后缀自动机来说,我们动态往里添加一 ...

  2. 求字符串中汉字的个数

    一.分解字符串法 首先创建这个函数: /*将字符串分解*/ create function [dbo].[SplitChar] ( @str_One Nvarchar(100) ) returns @ ...

  3. python求字符串中循环节个数

    此题来自今日头条2017秋招真题,题目叫String Shifting,其实就是求字符串中循环节个数 题目描述: 我们规定对一个字符串的shift操作如下: shift("ABCD" ...

  4. java求最大子串_Java获取两个字符串中最大相同子串的方法

    "abcwerthelloyuiodef" "cvhellobnm" 思路: 1,将短的那个子串按照长度递减的方式获取到. 2,将每获取到的子串去长串中判断是否 ...

  5. python在长字符串中寻找重复子串_Python 入门到精通

    1.变量 1.python不用事先声明变量,赋值过程中就包含了变量声明和定义的过程 2.用"="赋值,左边是变量名,右边是变量的值 1.1. 数字 整数 int_var = 1 长 ...

  6. python回文子串_LeetCode 647. 回文子串 | Python

    647. 回文子串 题目 给定一个字符串,你的任务是计算这个字符串中有多少个回文子串. 具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被视作不同的子串. 示例 1: 输入:" ...

  7. 字符串匹配:字符串中查找某子串

    字符串匹配:字符串中查找某子串 需求 具体算法 常规方法 程序 KMP算法 程序 后续 需求 我们在平时的软件开发,尤其是嵌入式开发,字符串匹配是非常重要的一个算法.而目前常用的字符串匹配算法有很多, ...

  8. JAVA版本:给定一个字符串,返回字符串中小写英文字母的个数、数字个数以及其他字符的个数

    给定一个字符串,返回字符串中小写英文字母的个数.数字个数以及其他字符的个数 方法分析:使用replaceAll()方法,逐一删除字符串中的相关数据,类型个数=原长度-新长度 public static ...

  9. 输入字符串中含有该字符的个数

    2019独角兽企业重金招聘Python工程师标准>>> ##需求:写出一个程序,接受一个有字母和数字以及空格组成的字符串,和一个字符,然后输出输入字符串中含有该字符的个数.不区分大小 ...

最新文章

  1. python列出文件夹所有文件_python-列出所有目录及子目录文件
  2. golang版try..catch..
  3. 布隆过滤器避免redis缓存穿透
  4. 向linux内核版本号添加字符/为何有时会自动添加“+”号
  5. 假如你学过高数,那你这一辈子都不会忘记这个人
  6. html5游戏制作入门系列教程(五)
  7. Redis操作命令(一)
  8. [debug] PyCharm 退出 pytest in XXX.py,恢复run XXX.py
  9. 陀螺仪数据转换成角度_请教怎么把用陀螺仪积分得到的角度转换到大地坐标系下?...
  10. linux在路径下创建文件,从可以在Linux中打开的文件路径创建文件
  11. python飞机大战类_500行代码,教你用python写个微信飞机大战
  12. Excel控制AutoCad进行坐标标注
  13. 04 数据清洗与准备
  14. ROS 2 Crystal Clemmys版机器人操作系统补充说明
  15. 工科数学分析寒假预习day3 一般级数的敛散性
  16. stm32连接热敏打印机
  17. Pandas中,使用reindex方法报错:index must be monotonic increasing or decreasing的分析
  18. 1.3 基于协同过滤的电影推荐案例
  19. 搭建WebRTC服务器
  20. hdfs大概流程和命令操作

热门文章

  1. win10新建虚拟机网络配置未连接服务器,win10虚拟主机怎么联网(win10虚拟机连不上网)...
  2. Linux下gunicorn用法
  3. @Column注解解析
  4. Soot 静态分析框架(二)Soot的核心
  5. binlog是什么?能做什么?Window下怎么开启binlog?怎么查看binlog日志?利用binlog日志恢复数据
  6. Java8中文api汉化文档下载【谷歌翻译最精准版】【jdk api 1.8_google.CHM】
  7. 分析IBinder体系中getService的流程
  8. html用九张图片做出九宫图,.九图片详解和制作
  9. Fio 命令生产环境测试
  10. 斐波拉契数列 Java三种实现