迴文串問題
解釋一下爲什麼會記錄刷題過程。記得研一爲了算法課刷題,曾經在本子中記錄過思路和代碼。這些算法思想,平常也沒機會使用,長時間不用,忘得比較快,再加上本子不易保存和現在電子閱讀的普及,所以就導致複習不好複習,還得從頭再來,所以這次刷題就記錄下來,發在csdn和知乎,以便隨時觀看。
最長迴文子串
給定一個字符串 s,找到 s 中最長的迴文子串。你可以假設 s 的最大長度爲 1000。
思路: 最長迴文子串問題的解決方法有常見的,還有神奇的,被稱爲馬拉車算法。對於算法,是考慮到迴文串的對稱性,每次循環選擇一箇中心,左右擴展,直到左右字符不再相等。考慮到字符串長度的奇偶性,爲了全面尋找最長迴文串,需要從一個字符開始擴展,或者從兩個字符間開始擴建,有2n-1箇中心點。
class Solution {
public:
string longestPalindrome(string s) {
int len = s.length();
if(len==0) return "";
int left=0, right=0;
for(int i=0;i<len;i++){
int len_1 = expand(s, i, i);
int len_2 = expand(s, i, i+1);
int len = len_1 > len_2 ? len_1 : len_2;
if((right - left) < len){
left = i - (len - 1) / 2;
right = i + len / 2;
}
}
return s.substr(left, (right - left + 1));
}
int expand(string s, int left, int right){
while(left>=0&&right<s.length()&&s[left]==s[right]){
left--;
right++;
}
return right - left - 1;
}
};
馬拉車算法(Manacher’s Algorithm)
馬拉車算法將時間複雜度降到了,但是空間複雜度爲。上述的中心擴展法的空間複雜度爲,用空間換取時間。
中心擴展的時候需要考慮到字符串奇偶性,假設字符串長度爲,通過加入個分隔符使得字符串長度爲奇數,將“babad”處理成“#b#a#b#a#d#"。
設置目前回文串的對稱中心點爲Center,迴文半徑長度爲Radius,右邊到達最遠爲Right=Center+Radius,當前點爲,關於Center的對稱點爲。記錄每個點回文字符串半徑的矩陣爲。
我們需要根據i和Right的大小來計算。
-
當時,如果,那麼可以根據迴文串對稱性得到;否則,超越界限,所以需要取,然後再左右擴展
-
如果,此時鏡像預測不起作用,,需左右擴展。
class Solution {
public:
string pre_process(string s){
int len = s.length();
len = 2 * len + 1;
string str="";
for(int i=0;i<len;i++){
if(i%2==0){
str += '#';
}else{
str += s[i/2];
}
}
return str;
}
string longestPalindrome(string s) {
string str = pre_process(s);
int len = str.length();
vector<int> P(len, 0);
int c = 0, r = 0;
int max_length = INT_MIN;
int max_index = 0;
for(int i=0;i<len;i++){
int i_mirror = 2 * c - i;
if(r>i){
P[i] = min(r-i, P[i_mirror]);
}
while(((i+P[i])<len)&&((i-P[i])>=0)&&str[i+P[i]]==str[i-P[i]]){
P[i]++;
}
if((i+P[i]) > r){
c = i;
r = i+P[i];
}
if(max_length < P[i]){
max_index= i;
max_length = P[i];
}
}
return s.substr((max_index - max_length + 1)/2, max_length-1);
}
};
迴文子串
給定一個字符串,你的任務是計算這個字符串中有多少個迴文子串。
具有不同開始位置或結束位置的子串,即使是由相同的字符組成,也會被計爲是不同的子串。
思路: 簡單暴力,我們搜索每一箇中心點。假設字符串長度爲,按照擴展算法的描述,有中心,對每一中心進行擴展,如果是迴文串,則記錄下來。
class Solution {
public:
int countSubstrings(string s) {
int len = s.length();
len = len*2-1;
int left=0,right=0;
int num = 0;
for(int i=0;i<len;i++){
left = i/2;
right = left + i%2;
while(left>=0&&right<len&&s[left]==s[right]){
left--;
right++;
num++;
}
}
return num;
}
};