c语言马拉车算法,最长回文子串(动规,中心扩散法,Manacher算法)

题目

解法

动态规划

时间复杂度\(O(n^2)\),空间复杂度\(O(n^2)\)

基本解法直接看代码

class Solution {

public:

string longestPalindrome(string s) {

int n = s.size();

vector> dp(n, vector(n, true));

int rx, ry;

rx = ry = 0;

for(int l = 1; l < n; l++){

for(int i = 0; i < n - l; i++){

int j = i + l;

if(s[i] == s[j] && (j - i < 3 || dp[i+1][j-1])){

dp[i][j] = true;

if(j - i > ry - rx){

ry = j;

rx = i;

}

} else {

dp[i][j] = false;

}

}

}

return s.substr(rx, ry - rx + 1);

}

};

中心扩散法

时间复杂度\(O(n^2)\),空间复杂度\(O(1)\)

我们先假定以某点为中心向两端扩散,找到以该点为中心的最长回文子串

class Solution {

public:

int rx, ry;

void helper(string &s, int i, int offset){

int left = i;

int right = i + offset;

while(left >= 0 && right < s.size() && s[left] == s[right]){

left--;

right++;

}

if(right - 1 - (left + 1) > ry - rx){

ry = right - 1;

rx = left + 1;

}

}

string longestPalindrome(string s) {

int n = s.size();

rx = ry = 0;

for(int i = 0; i < n; i++){

helper(s, i, 0);

helper(s, i, 1);

}

return s.substr(rx, ry - rx + 1);

}

};

Manacher算法

Manacher算法俗称“马拉车算法”,时间复杂度\(O(n)\),空间复杂度\(O(n)\)

因为回文字符串都有奇数长度的串和偶数长度的串,为了更好处理这两种情况,可以在字符串中插入一特殊字符'#',使得新字符串长度全变为奇数长度,如"aa"变为"#a#a#",可以再字符串首部加入另一特殊字符'$',这样就不用特殊处理越界问题(同一边界处理)

以"122112321"为例经过上一步变成"$#1#2#2#1#1#2#3#2#1#"

Manacher算法使用一个辅助数组r[i]表示以t[i]为中心的最长回文子串的最右字符到t[i]的长度,如以t[i]为中心的最长回文子串为t[low, high],则r[i] = high - i + 1, t[low, high] = 2 * r[i]-1, len数组有一个性质,就是r[i]-1为该回文子串在原串中的长度,证明很简单t[lowl, high]一定是以"#"开头和结尾的,这样插入的"#"是原来串中字符的两倍还多一个,这样原串中最长回文串的长度就为r[i]-1,这样问题就转为求最长的r[i]

计算len数组

算法主要利用了已有的回文子串的特点,减少了查找时间,从左往右计算len[i],同时保存一个之前计算最长回文子串的右端点的最大值R及对应的中心位置c,

i < R, 则先找i关于id对称点j=2*id-1,则至少r[i] \(\geq\) min(R - i + 1, p[j]), 超出部分再手工匹配

i >= R, 则不能利用以后的知识做任何假设,只能假定其至少为1

class Solution {

public:

string longestPalindrome(string s) {

int n = s.size();

if(n == 0) return "";

string ns;

ns.push_back('$');

for(int i = 0; i < n; i++){

ns.push_back('#');

ns.push_back(s[i]);

}

ns.push_back('#');

ns.push_back('@');

n = ns.size();

vector r(n);

int c, R, C, MAX;

R = -1;

MAX = 0;

C = 0;

for(int i = 1; i < n; i++){

r[i] = i < R ? min(r[2 * c - i], R - i + 1) : 1;

while(ns[i + r[i]] == ns[i - r[i]]) r[i]++;

r[i]--;

if(i + r[i] > R){

R = i + r[i];

c = i;

}

if(r[i] > MAX){

MAX = r[i];

C = i;

}

}

return s.substr((C-MAX)/2, r[C]);

}

};

时间复杂度分析

参考

标签:string,int,Manacher,rx,ry,ns,动规,回文

来源: https://www.cnblogs.com/qbits/p/11229279.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值