-
Notifications
You must be signed in to change notification settings - Fork 4.9k
/
ShortestPalindrome.cpp
193 lines (173 loc) · 5.61 KB
/
ShortestPalindrome.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
// Source : https://leetcode.com/problems/shortest-palindrome/
// Author : Hao Chen
// Date : 2015-06-11
/**********************************************************************************
*
* Given a string S, you are allowed to convert it to a palindrome by adding characters in front of it.
* Find and return the shortest palindrome you can find by performing this transformation.
*
* For example:
* Given "aacecaaa", return "aaacecaaa".
* Given "abcd", return "dcbabcd".
*
* Credits:Special thanks to @ifanchu for adding this problem and creating all test cases.
* Thanks to @Freezen for additional test cases.
*
**********************************************************************************/
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
bool isPalindrome(string& s, int begin, int end) {
for (; begin<end; begin++, end-- ) {
if ( s[begin] != s[end] ) {
return false;
}
}
return true;
}
// Burst Force - - Time Limit Error
string shortestPalindrome_bf(string& s) {
int len = s.size();
int i;
for (i=len-1; i>=0; i--) {
if (isPalindrome(s, 0, i)) {
i++;
break;
}
}
string t = s.substr(i, len-i);
reverse(t.begin(), t.end());
return t+s;
}
//Dynamic Programming - Memory Limit Exceeded & Time Limit Error
// Using the method of finding longest palindrome
string shortestPalindrome_dp(string& s) {
int len = s.size();
if (len <=1 ) return s;
//find longest palindrome, see "Longest Palindromic Substring"
vector< vector<bool> > dp(len, vector<bool>(len, false));
for (int i=len-1; i>=0; i--){
for(int j=i; j<len; j++){
if (i==j || ((j-i==1 || dp[i+1][j-1]) && s[i]==s[j]) ) {
dp[i][j] = true;
}
}
}
/*
* // only use two lines -- still have Time Limit Error
*
* vector< vector<bool> > dp(2, vector<bool>(len, false));
* for (int i=len-1; i>=0; i--){
* for(int j=i; j<len; j++){
* if (i==j || ((j-i==1 || dp[(i+1)%2][j-1]) && s[i]==s[j]) ) {
* dp[i%2][j] = true;
* }
* }
* }
*/
//find the longest palindrome which start from first char.
int pos = 0;
for (int i=1; i<len; i++) {
if (dp[0][i]) {
pos = i+1;
}
}
string t = s.substr(pos, len - pos);
reverse(t.begin(), t.end());
return t+s;
}
/*
* The core of KMP algorithm needs to build a partial match table for pattern,
* which can determin how many chars need to skip if mismatch happens.
*
* The best explaination of the idea of the KMP algorithm is:
* http://jakeboxer.com/blog/2009/12/13/the-knuth-morris-pratt-algorithm-in-my-own-words/
*
* Here, we can use KMP algorithm to solve this problem.
*
* 1) We need construct a mirror string base on original string. and use a uniq char for seperator.
*
* considering the original string is "abab", then the mirror string is "abab#baba" (# is seperator)
*
* 2) Build the KMP partial match table for this pattern.
*
* a b a b # b a b a
* 0 0 1 2 0 0 1 2 3
*
* 3) Checking the last position of partial match table, it is 3. it means:
*
* For the entire pattern (mirror string), there has max 3 length of sub-string is both prefix and suffix.
*
* This sub-string is "aba".
*
* 4) The result of 3) is really useful to solve this shorest palindrome problem.
*
* Because "aba" is the pattern which in original string and its reversed version.
*
* ( Note: The uniq char is used for making the noise, which can make sure
* the original string and its reversed version won't be mixed.
* then, the common prefix and suffix sub-string is right )
*
* So, if a sub-string "aba" is existed in both original string and its reversed version,
* which means, this is the longest prefix palindrome.
*
* 5) Then, we can take rest suffix, and reverse it and put it in front of original string.
*
*/
string shortestPalindrome_kmp(string& s) {
int len = s.size();
if(len <= 1) return s;
string pattern = s + '\0' + string(s.rbegin(), s.rend());
//construct the partial match table
vector<int> prefix( pattern.size() );
prefix[0] = 0;
for(int i = 1; i < prefix.size(); i++) {
int j = prefix[i-1];
while( j > 0 && pattern[i] != pattern[j] ) {
j = prefix[j-1];
}
if ( pattern[i] == pattern[j] ) {
j++;
}
prefix[i] = j;
}
#ifdef _DEBUG
cout << endl;
for(int i=0; i<pattern.size(); i++){
cout << (pattern[i] ? pattern[i] : '#') << " ";
}
cout << endl;
for(int i=0; i<prefix.size(); i++) {
cout << prefix[i] << " ";
}
cout << endl;
cout << "-->" << s.substr(0, prefix.back()) << " " << s.substr(prefix.back()) << endl;
#endif
int pos = s.size() - prefix.back();
return string(s.rbegin(), s.rbegin() + pos) + s;
}
string shortestPalindrome(string s) {
return shortestPalindrome_kmp(s);
return shortestPalindrome_dp(s); //Memory Limit Error
return shortestPalindrome_bf(s); //Time Limit Error
}
#define TEST(s) cout << s << " : " << shortestPalindrome(s) << endl
int main(int argc, char**argv)
{
string s = "aabba";
if (argc>1){
s = argv[1];
}
TEST(s);
TEST("a");
TEST("ab");
TEST("aba");
TEST("abab");
TEST("aabb");
TEST("aacecaaa");
TEST("abcd");
TEST("aaabcb");
return 0;
}