UVA - 11475 Extend to Palindrome —— 字符串哈希 or KMP or 后缀数组

题目链接:https://vjudge.net/problem/UVA-11475

 

 

题意:

给出一个字符串,问在该字符串后面至少添加几个字符,使得其成为回文串,并输出该回文串。

 

题解:

实际上是求该字符串的“最长回文后缀”,有多种做法,其中用字符串哈希的方法最方便而且速度最快。

 

 

字符串哈希:

从字符串的最后一个字符开始,往前进行计算两个哈希值,其中一个按“先高位后低位”的方法计算,另一个按“先低位后高位”的方法计算。如果在某个位置,两个哈希值相等,那么表明该后缀为回文串,求最长的那个即可。

 

代码如下:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 #include <vector>
 6 #include <cmath>
 7 #include <queue>
 8 #include <stack>
 9 #include <map>
10 #include <string>
11 #include <set>
12 using namespace std;
13 typedef long long LL;
14 const int INF = 2e9;
15 const LL LNF = 9e18;
16 const int MOD = 1e9+7;
17 const int MAXN = 2e5+100;
18 
19 const LL seed = 13331;
20 char str[MAXN];
21 int main()
22 {
23     while(scanf("%s",str)!=EOF)
24     {
25         int len = strlen(str);
26         int pos = len-1;
27         LL hash1 = 0, hash2 = 0, s = 1;
28         for(int i = len-1; i>=0; i--)
29         {
30             hash1 *= seed, hash1 += str[i];
31             hash2 += str[i]*s, s *= seed;
32             if(hash1==hash2)
33                 pos = i-1;
34         }
35         for(int i = 0; i<len; i++) putchar(str[i]);
36         for(int i = pos; i>=0; i--) putchar(str[i]);
37         putchar('\n');
38     }
39 }
View Code

 

 

KMP:

1. 根据next数组的next[len]即为字符串前缀与后缀的最长匹配(不包括重叠的情况),可以将字符串的逆串接在其前面,中间用一个分割符隔开,得到新串,求出新串的next数组

1.1 逆串放在前面是因为用逆串的前缀去匹配原串的后缀。

1.2 中间加个分隔符是用于防止逆串匹配到逆串那里去,即防止过界。

2. 假设新串的长度为len, 那么next[len]即为可节省的最大长度,因而只需添加len-next[len]个字符即可。

 

代码如下:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 #include <vector>
 6 #include <cmath>
 7 #include <queue>
 8 #include <stack>
 9 #include <map>
10 #include <string>
11 #include <set>
12 using namespace std;
13 typedef long long LL;
14 const int INF = 2e9;
15 const LL LNF = 9e18;
16 const int MOD = 1e9+7;
17 const int MAXN = 2e5+100;
18 
19 char x[MAXN];
20 int Next[MAXN];
21 void get_next(char x[], int m)
22 {
23     int i, j;
24     j = Next[0] = -1;
25     i = 0;
26     while(i<m)
27     {
28         while(j!=-1 && x[i]!=x[j]) j = Next[j];
29         Next[++i] = ++j;
30     }
31 }
32 
33 char str[MAXN];
34 int main()
35 {
36     while(scanf("%s",str)!=EOF)
37     {
38         int len = strlen(str);
39         int m = 2*len+1;
40         for(int i = 0; i<len; i++)
41         {
42             x[len-1-i] = str[i];
43             x[len+1+i] = str[i];
44         }
45         x[len] = '$'; x[m] = 0;
46         get_next(x, m);
47 
48         int pos = len-Next[m]-1;
49         for(int i = 0; i<len; i++) putchar(str[i]);
50         for(int i = pos; i>=0; i--) putchar(str[i]);
51         putchar('\n');
52     }
53 }
View Code

 

 

后缀数组:

1.将逆串接在原串的后面,中间用一个分隔符隔开,得到新串。求出新串的后缀数组。

2.枚举原串在新串中的每一个位置i,该位置代表着新串的一个后缀i,设逆串首字符在原串中的位置为j,同样代表着新串的一个后缀j。加入后缀i与后缀j个最长公共前缀lcp满足:i+lcp==len,即表明最长公共前缀已经延伸到原串的串尾,所以该原串的后缀i为回文串。同样,求出最长的那个即可。

 

代码如下:

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #include <vector>
  6 #include <cmath>
  7 #include <queue>
  8 #include <stack>
  9 #include <map>
 10 #include <string>
 11 #include <set>
 12 using namespace std;
 13 typedef long long LL;
 14 const int INF = 2e9;
 15 const LL LNF = 9e18;
 16 const int MOD = 1e9+7;
 17 const int MAXN = 2e5+100;
 18 
 19 bool cmp(int *r, int a, int b, int l)
 20 {
 21     return r[a]==r[b] && r[a+l]==r[b+l];
 22 }
 23 
 24 int r[MAXN], sa[MAXN], Rank[MAXN], height[MAXN];
 25 int t1[MAXN], t2[MAXN], c[MAXN];
 26 void DA(int str[], int sa[], int Rank[], int height[], int n, int m)
 27 {
 28     n++;
 29     int i, j, p, *x = t1, *y = t2;
 30     for(i = 0; i<m; i++) c[i] = 0;
 31     for(i = 0; i<n; i++) c[x[i] = str[i]]++;
 32     for(i = 1; i<m; i++) c[i] += c[i-1];
 33     for(i = n-1; i>=0; i--) sa[--c[x[i]]] = i;
 34     for(j = 1; j<=n; j <<= 1)
 35     {
 36         p = 0;
 37         for(i = n-j; i<n; i++) y[p++] = i;
 38         for(i = 0; i<n; i++) if(sa[i]>=j) y[p++] = sa[i]-j;
 39 
 40         for(i = 0; i<m; i++) c[i] = 0;
 41         for(i = 0; i<n; i++) c[x[y[i]]]++;
 42         for(i = 1; i<m; i++) c[i] += c[i-1];
 43         for(i = n-1; i>=0; i--) sa[--c[x[y[i]]]] = y[i];
 44 
 45         swap(x, y);
 46         p = 1; x[sa[0]] = 0;
 47         for(i = 1; i<n; i++)
 48             x[sa[i]] = cmp(y, sa[i-1], sa[i], j)?p-1:p++;
 49 
 50         if(p>=n) break;
 51         m = p;
 52     }
 53 
 54     int k = 0;
 55     n--;
 56     for(i = 0; i<=n; i++) Rank[sa[i]] = i;
 57     for(i = 0; i<n; i++)
 58     {
 59         if(k) k--;
 60         j = sa[Rank[i]-1];
 61         while(str[i+k]==str[j+k]) k++;
 62         height[Rank[i]] = k;
 63     }
 64 }
 65 
 66 int dp[MAXN][20], mm[MAXN];
 67 void initRMQ(int n, int b[])
 68 {
 69     mm[0] = -1;
 70     for(int i = 1; i<=n; i++)
 71         dp[i][0] = b[i], mm[i] = ((i&(i-1))==0)?mm[i-1]+1:mm[i-1];
 72     for(int j = 1; j<=mm[n]; j++)
 73     for(int i = 1; i+(1<<j)-1<=n; i++)
 74         dp[i][j] = min(dp[i][j-1], dp[i+(1<<(j-1))][j-1]);
 75 }
 76 
 77 int RMQ(int x, int y)
 78 {
 79     if(x>y) swap(x, y);
 80     x++;
 81     int k = mm[y-x+1];
 82     return min(dp[x][k], dp[y-(1<<k)+1][k]);
 83 }
 84 
 85 char str[MAXN];
 86 int main()
 87 {
 88     while(scanf("%s", str)!=EOF)
 89     {
 90         int len = strlen(str);
 91         int n = 2*len+1;
 92         for(int i = 0; i<len; i++)
 93         {
 94             r[i] = str[i];
 95             r[n-1-i] = str[i];
 96         }
 97         r[len] = '$'; r[n] = 0;
 98         DA(r, sa, Rank, height, n, 128);
 99         initRMQ(n, height);
100 
101         int pos = len-1;
102         for(int i = 0; i<len; i++)
103         {
104             int lcp = RMQ(Rank[i], Rank[len+1]);
105             if(i+lcp==len)
106             {
107                 pos = i-1;
108                 break;
109             }
110         }
111         for(int i = 0; i<len; i++) putchar(str[i]);
112         for(int i = pos; i>=0; i--) putchar(str[i]);
113         putchar('\n');
114     }
115 }
View Code

 

posted on 2018-02-27 14:33  h_z_cong  阅读(229)  评论(0编辑  收藏  举报

导航