leetcode-7:迴文串問題

迴文串問題

解釋一下爲什麼會記錄刷題過程。記得研一爲了算法課刷題,曾經在本子中記錄過思路和代碼。這些算法思想,平常也沒機會使用,長時間不用,忘得比較快,再加上本子不易保存和現在電子閱讀的普及,所以就導致複習不好複習,還得從頭再來,所以這次刷題就記錄下來,發在csdn和知乎,以便隨時觀看。

最長迴文子串

給定一個字符串 s,找到 s 中最長的迴文子串。你可以假設 s 的最大長度爲 1000。

思路: 最長迴文子串問題的解決方法有常見的O(n2)O\left(n^{2}\right),還有神奇的O(n)O\left(n\right),被稱爲馬拉車算法。對於O(n2)O\left(n^{2}\right)算法,是考慮到迴文串的對稱性,每次循環選擇一箇中心,左右擴展,直到左右字符不再相等。考慮到字符串長度的奇偶性,爲了全面尋找最長迴文串,需要從一個字符開始擴展,或者從兩個字符間開始擴建,有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)

馬拉車算法將時間複雜度降到了O(n)O\left(n\right),但是空間複雜度爲O(n)O\left(n\right)。上述的中心擴展法的空間複雜度爲O(1)O\left(1\right),用空間換取時間。

中心擴展的時候需要考慮到字符串奇偶性,假設字符串長度爲nn,通過加入n+1n+1個分隔符使得字符串長度爲奇數2n+12n+1,將“babad”處理成“#b#a#b#a#d#"。

設置目前回文串的對稱中心點爲Center,迴文半徑長度爲Radius,右邊到達最遠爲Right=Center+Radius,當前點爲iiii關於Center的對稱點爲i_mirror=2Centerii\_mirror = 2 *Center - i。記錄每個點回文字符串半徑的矩陣爲PP

我們需要根據i和Right的大小來計算P[i_mirror]P[i\_mirror]

  • i<Righti < Right時,如果i+P[i_mirror]>=Ri + P[i\_mirror] >= R,那麼可以根據迴文串對稱性得到P[i]=P[i_mirror]P[i] = P[i\_mirror];否則,超越界限,所以需要取min(P[i_mirror],Ri)min(P[i\_mirror], R-i),然後再左右擴展

  • 如果i>Ri > R,此時鏡像預測不起作用,P[i]=0P[i] = 0,需左右擴展。

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);
    }
};

迴文子串

給定一個字符串,你的任務是計算這個字符串中有多少個迴文子串。
具有不同開始位置或結束位置的子串,即使是由相同的字符組成,也會被計爲是不同的子串。

思路: 簡單暴力,我們搜索每一箇中心點。假設字符串長度爲nn,按照擴展算法的描述,有2n+12*n+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;
    }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章