首页 > 试题广场 >

Manacher算法进阶问题

[编程题]Manacher算法进阶问题
  • 热度指数:588 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
给定一个字符串str,想通过添加字符的方式使得str整体都变成回文字符串,但要求只能在str的末尾添加字符,请返回在str后面添加的最短字符串
[举例]
str = "abcd123321",在必须包含最后一个字符的情况下,最长的回文子串是"123321",之前不是最长回文子串的部分是'abcd",所以末尾应该添加的部分就是"dcba"。
[要求]
如果str的长度为N,解决进阶问题的时间复杂度为O(N).
保证输入数据无回文串

输入描述:
输入为一个字符串str


输出描述:
输出一个字符串。
示例1

输入

abcd123321

输出

dcba

说明

添加后的字符串为abcd123321dcba
示例2

输入

ababab

输出

a

备注:
设N表示输入字符串的长度
保证输入字符中只含有小写字母及数字
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.util.*;
 
public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String s = br.readLine();
        char[] str = preprocessing(s.toCharArray());     // 预处理原始字符串,往每个字符之间加#
        int C = -1;
        int R = -1;
        int[] pArr = new int[str.length];
        for(int i=0; i<str.length; i++){
            pArr[i] = i<R ? Math.min(pArr[2*C-i],R-i) : 1;
            while(i+pArr[i]<str.length && i-pArr[i]>-1){
                if(str[i-pArr[i]]==str[i+pArr[i]]){
                    pArr[i]++;
                }else{
                    break;
                }
            }
            if(i+pArr[i]>R){
                R=i+pArr[i];
                C = i;
            }
        }
        int index= C-pArr[C];
        StringBuilder sb = new StringBuilder();
        while(index>=0){
            sb.append(str[index]=='#' ? "" : str[index]);
            index--;
        }
        System.out.println(sb.toString());
    }
     
    private static char[] preprocessing(char[] str) {
        StringBuilder sb = new StringBuilder();
        for(char c: str) sb.append("#").append(c);
        sb.append("#");
        return sb.toString().toCharArray();
    }
}

发表于 2022-01-26 20:20:41 回复(0)
#include <iostream>
#include <string>
#include <algorithm>
#include <limits.h>
#include <vector>
using namespace std;

string fillStr(string s){
    string str(s.size() * 2 + 1, '#');
    for(int i = 0; i < s.size(); i++){
        str[2 * i + 1] = s[i];
    }
    return str;
}

int manacher(string s){
    string str = fillStr(s);
    int R = -1;
    int C = -1;
    vector<int> pArr(str.size(), 0);
    int maxVal = INT_MIN;
    for(int i = 0; i < str.size(); i++){
        pArr[i] = i < R ? min(pArr[2 * C - i], R - i) : -1;
        while(i + pArr[i] < str.size() && i - pArr[i] > -1){
            if(str[i + pArr[i]] == str[i - pArr[i]]){
                pArr[i]++;
            }
            else
                break;
        }
        if(i + pArr[i] > R){
            R = i + pArr[i];
            C = i;
        }
        if(R == str.size()){
            maxVal = max(maxVal, pArr[i]);
        }
    }
    return maxVal < 0 ? 0 : maxVal - 1;
}

int main(void){
    string s;
    cin >> s;
    int maxVal = manacher(s);
    string ans = s.substr(0, s.size() - maxVal);
    reverse(ans.begin(), ans.end());
    cout << ans << endl;
    return 0;
}
这道题解法在于知道马拉车算法怎么求
再次基础上要求最大回文子串,加了个限制条件 R = str.size()
在此基础上s.sbustr() 再reverse就可以了
发表于 2021-05-28 11:39:03 回复(0)
manacher   找到最后一个center

int main()
{
    string str;
    cin>>str;
    string s;
    s+='#';
    for(int i=0;i<str.size();i++)
    {
        s+=str[i];
        s+='#';
    }
    //预处理
    int len=s.size();//预处理后的长度
    vector<int> dp(len,0);//dp[i]表示i位置的可以向外回文延长的长度、
    int center=0;
    int max_right=0;
    for(int i=1;i<len;i++)
    {
        //计算dp[i]
        if(i<max_right)
            dp[i]=min(dp[2*center-i],max_right-i);
        else
            dp[i]=1;
        while(i-dp[i]>0 && i+dp[i]<len && s[i-dp[i]]==s[i+dp[i]])
            dp[i]++;
        if(i+dp[i]>max_right)
        {
            max_right=i+dp[i];
            center=i;
        }
    }
    for(int i=2*center-len;i>=0;i--)
        if(i%2==1)         //过滤掉'#'
            cout<<s[i]; 
}




发表于 2020-12-05 01:12:36 回复(0)
#include<cstdio>
(802)#include<cstring>
bool ishuiwen(char str[],int l,int r){
    int k=0;
    for(int i=l;i<=(l+r)/2;++i){
        if(str[i]!=str[r-k])
            return false;
        ++k;
    }
    return true;
}
int main(){
    char str[500010];
    while(scanf("%s",str)!=EOF){
        int len=strlen(str);
        int i;
        for(i=0;i<len;++i){
            if(ishuiwen(str,i,len-1))
                break;
        }
        for(i=i-1;i>=0;--i){
        	printf("%c",str[i]);
        }
    }
    return 0;
}

发表于 2020-03-25 15:43:32 回复(0)