Given a string S, you are allowed to convert it to a palindrome by adding 0 or more characters in front of it.
Find the length of the shortest palindrome that you can create from S by applying the above transformation.
Answer:
Best solution here is to use a Knuth-Morris-Pratt algorithm. It runs in
O(n) time, requires 2*n additional space and extremely fast and easy to
code. The main idea is - we construct new string that contains our
string + some symbol that can't be in our string, for instance '$' +
reversed our string. After that we need to run KMP for that string to
calculate prefix function. The answer is the length of our starting
string minus prefix function value of the last element of the new
string.
prefix function for every position i in the string shows the maximum
length of prefix for the string s [0...i] that equals to suffix of the
string s[0...i].
So if we construct new string in the way described above, prefix
function for the last element will show the maximum size of the
palindrome in the beginning of our string. All we have to do is to add
in front of our string the rest of the characters.
int getPalindrome(string s) {
int n = s.size();
vector<int> p(2*n+1,0);
string current = s + '$';
for (int i = 0; i < n; i++) {
current += s[n - 1 - i];
}
p[0] = 0;
for (int i = 1; i < 2 * n + 1; i++) {
int j = p[i - 1];
while (j > 0 && current[j] != current[i])
j = p[j - 1];
j += current[i] == current[j];
p[i] = j;
}
return 2 *n - p[2 * n];//returns the length of the palindrome formed
}
Showing posts with label kmp. Show all posts
Showing posts with label kmp. Show all posts
Wednesday, December 3, 2014
Wednesday, November 19, 2014
string question: example using kmp
A家的电面题:
有一种String,是把一个更短的String重复n次而构成的,那个更短的String长度至少为
2,输入一个String写代码返回T或者F
例子:
"abcabcabc" Ture 因为它把abc重复3次构成
"bcdbcdbcde" False 最后一个是bcde
"abcdabcd" True 因为它是abcd重复2次构成
"xyz" False 因为它不是某一个String重复
"aaaaaaaaaa" False 重复的短String长度应至少为2(这里不能看做aa重复5次)
要求算法复杂度为O(n)
public boolean isMultiple(String s){
}
Ans:
用KMP吧。检查preprocess部分生产的array pai 就可以了。如果是valid case.
preprocessing array 必然满足下面的几个条件:
1. pai[n-1] 必须是最大值 (这个没必要专门检查,只要3满足就成);
2. s[0,...,n-pai[n-1])就是repeating pattern;
3. pai[n-1]/(length of the repeating pattern) >= 1;
4. pai[n-1] % (length of the repeating pattern) == 0.
bool isMultiple(const string &text){
int n=text.length();
vector<int> pai(n);
computeVec(text,pai);
int len=n-pai[n-1];
return len>1&&pai[n-1]/len>=1&&pai[n-1]%len==0;
}
void computeVec(const string &Pat, vector<int>&pai){//from KMP
pai[0]=0;
int k=0;
int m=Pat.length();
for(int i=1;i<m;i++){
while(k>0&&Pat[k]!=Pat[i])
k=pai[k-1];
if(Pat[k]==Pat[i])
k++;
pai[i]=k;
}
}
有一种String,是把一个更短的String重复n次而构成的,那个更短的String长度至少为
2,输入一个String写代码返回T或者F
例子:
"abcabcabc" Ture 因为它把abc重复3次构成
"bcdbcdbcde" False 最后一个是bcde
"abcdabcd" True 因为它是abcd重复2次构成
"xyz" False 因为它不是某一个String重复
"aaaaaaaaaa" False 重复的短String长度应至少为2(这里不能看做aa重复5次)
要求算法复杂度为O(n)
public boolean isMultiple(String s){
}
Ans:
用KMP吧。检查preprocess部分生产的array pai 就可以了。如果是valid case.
preprocessing array 必然满足下面的几个条件:
1. pai[n-1] 必须是最大值 (这个没必要专门检查,只要3满足就成);
2. s[0,...,n-pai[n-1])就是repeating pattern;
3. pai[n-1]/(length of the repeating pattern) >= 1;
4. pai[n-1] % (length of the repeating pattern) == 0.
bool isMultiple(const string &text){
int n=text.length();
vector<int> pai(n);
computeVec(text,pai);
int len=n-pai[n-1];
return len>1&&pai[n-1]/len>=1&&pai[n-1]%len==0;
}
void computeVec(const string &Pat, vector<int>&pai){//from KMP
pai[0]=0;
int k=0;
int m=Pat.length();
for(int i=1;i<m;i++){
while(k>0&&Pat[k]!=Pat[i])
k=pai[k-1];
if(Pat[k]==Pat[i])
k++;
pai[i]=k;
}
}
Tuesday, November 18, 2014
kmp string match
from CLRS(Introduction to Algorithm)
For a pattern P, pai[q] is the length of the longest prefix of P that is a proper suffix of Pq. (Pq is P[1...q], note that here the index start from 1, which is different from the code below)
vector<int> computepai(string Pat){
int n=Pat.length();
vector<int> pai(n,0);
pai[0]=0;
for(int i=1;i<n;i++){
int k=pai[i-1];//number of characters matched
while(k>0&&Pat[k]!=Pat[i])
k=pai[k-1];
k+=Pat[k]==Pat[i];
pai[i]=k;
}
return pai;
}
下面这个computepai是算法导论上的版本,和上面的几乎一样(不同的只是k的位置),但是上面的似乎更容易理解和记忆些。
vector<int> computepai(string Pat){
int n=Pat.length();
vector<int> pai(n,0);
pai[0]=0;
int k=0;//number of characters matched
for(int i=1;i<n;i++){
while(k>0&&Pat[k]!=Pat[i])
k=pai[k-1];
if(Pat[k]==Pat[i])
k++;
pai[i]=k;
}
return pai;
}
void matchstr(string text,string Pat){
int n=text.length();
int m=Pat.length();
vector<int> pai= computepai(Pat);
int k=0;//number of characters matched
for(int i=0;i<n;i++){//scan the text from left to right
while(k>0&&Pat[k]!=text[i])
k=pai[k-1]; //next character of P doesn't match text[i]
if(Pat[k]==text[i])
k++; //next character matches
if(k==m){ // is all of P matched
cout<<"find in pos : "<<i-m+1<<" "<<text.substr(i-m+1,m)<<endl;
k=pai[k-1];
}
}
}
For a pattern P, pai[q] is the length of the longest prefix of P that is a proper suffix of Pq. (Pq is P[1...q], note that here the index start from 1, which is different from the code below)
vector<int> computepai(string Pat){
int n=Pat.length();
vector<int> pai(n,0);
pai[0]=0;
for(int i=1;i<n;i++){
int k=pai[i-1];//number of characters matched
while(k>0&&Pat[k]!=Pat[i])
k=pai[k-1];
k+=Pat[k]==Pat[i];
pai[i]=k;
}
return pai;
}
下面这个computepai是算法导论上的版本,和上面的几乎一样(不同的只是k的位置),但是上面的似乎更容易理解和记忆些。
vector<int> computepai(string Pat){
int n=Pat.length();
vector<int> pai(n,0);
pai[0]=0;
int k=0;//number of characters matched
for(int i=1;i<n;i++){
while(k>0&&Pat[k]!=Pat[i])
k=pai[k-1];
if(Pat[k]==Pat[i])
k++;
pai[i]=k;
}
return pai;
}
void matchstr(string text,string Pat){
int n=text.length();
int m=Pat.length();
vector<int> pai= computepai(Pat);
int k=0;//number of characters matched
for(int i=0;i<n;i++){//scan the text from left to right
while(k>0&&Pat[k]!=text[i])
k=pai[k-1]; //next character of P doesn't match text[i]
if(Pat[k]==text[i])
k++; //next character matches
if(k==m){ // is all of P matched
cout<<"find in pos : "<<i-m+1<<" "<<text.substr(i-m+1,m)<<endl;
k=pai[k-1];
}
}
}
Subscribe to:
Posts (Atom)