Peter's codebook A blog full of codes

LeetCode 5 Longest Palindromic Substring

Longest Palindromic Substring

傳送門

LeetCode 5

輸入輸出

Leet Code 比較特別,有點像是要你完成一個 Function ,所以下面的 Code 有在解答下,加上輸入出。

限制

它好像沒給(?)

程式碼:

先附上 的解法,之後再補上更好的。

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
/*
// On Leet Code
// Difficulty: Medium
class Solution {
    public:
        string longestPalindrome(string s) {
            string odds, evens;
            //odd
            for(int i=0; i!=s.length(); ++i) {
                int j=1;
                for(; i-j>=0&&i+j<s.length()&&s[i-j]==s[i+j]; ++j);
                --j;
                if(j*2+1>=odds.length()) {
                    odds.clear();
                    odds.insert(odds.end(), s.begin()+i-j, s.begin()+i+j+1);
                }
            }
            //even
            for(int i=1; i<s.length(); ++i) {
                int l=i-1, r=i;
                for(; l>=0&&r<s.length()&&s[l]==s[r]; --l,++r);
                if(s[++l]==s[--r]&&r-l+1>=evens.length()) {
                    evens.clear();
                    evens.insert(evens.end(), s.begin()+l, s.begin()+r+1);
                }
            }
            return evens.length()>odds.length()?evens:odds;
        }
};
*/
#include <bits/stdc++.h>
using namespace std;

string lps(string &s) {
    string odds, evens;
    //odd
    for(int i=0; i!=s.length(); ++i) {
        int j=1;
        for(; i-j>=0&&i+j<s.length()&&s[i-j]==s[i+j]; ++j);
        --j;
        if(j*2+1>=odds.length()) {
            odds.clear();
            odds.insert(odds.end(), s.begin()+i-j, s.begin()+i+j+1);
        }
    }
    //even
    for(int i=1; i<s.length(); ++i) {
        int l=i-1, r=i;
        for(; l>=0&&r<s.length()&&s[l]==s[r]; --l,++r);
        if(s[++l]==s[--r]&&r-l+1>=evens.length()) {
            evens.clear();
            evens.insert(evens.end(), s.begin()+l, s.begin()+r+1);
        }
    }
    return evens.length()>odds.length()?evens:odds;
}

int main(void) {
    string input;
    cin>>input;
    cout<<lps(input)<<endl;
    return 0;
}

Hash 版的(寫爛了,反而比較慢) 應該是

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
#include <bits/stdc++.h>
using namespace std;

#define PB push_back
#define F first
#define S second
typedef long long int UT;
typedef pair< UT, UT > PII;
const PII p(29,31), q(10000103, 10000121);
const int MAXN(1010);
PII h[MAXN], rh[MAXN], cache[MAXN];

class Solution {
    public:
        string longestPalindrome(string &s) {
            get_pow(cache, p, s.length(), q);//lazy dog
            get_hash(s,h); get_hash(s,rh,true);
            int lb=0, hb=s.length()/2+3;//No need to warry.
            int eoff=-1, ooff=-1;
            while(hb - lb > 1) {
                int mid=(lb+hb)/2;
                int idx = check(s.length(), h, rh, cache[mid*2], mid*2);
                if( idx!=-1 ) {
                    eoff=idx;
                    lb=mid;
                } else hb=mid;
            }
            int ev=lb;

            lb=0, hb=s.length()/2+3;
            while(hb - lb > 1) {
                int mid=(lb+hb)/2;
                int idx = check(s.length(), h, rh, cache[mid*2+1], mid*2+1);
                if( idx!=-1 ) {
                    ooff=idx;
                    lb=mid;
                } else hb=mid;
            }
            int od=lb;

            if(eoff!=-1 && ooff!=-1) {
                return od*2+1>ev*2?s.substr(ooff, od*2+1):s.substr(eoff, ev*2);
            }
            if(eoff!=-1) return s.substr(eoff, ev*2);
            if(ooff!=-1) return s.substr(ooff, od*2+1);
            return s.substr(0,1);
        }

        inline void get_hash(string &s, PII *h, bool rev=false) {
            h[0].F=h[0].S=h[s.length()+1].S=h[s.length()+1].F=0;
            ++h; // index is shifted
            if(!rev) {
                for(int i=0; i!=s.length(); ++i ){
                    h[i].F = ((h[i-1].F*p.F%q.F)+s[i]+1)%q.F;
                    h[i].S = ((h[i-1].S*p.S%q.S)+s[i]+1)%q.S;
                }
            } else { //reverse
                for(int i=s.length()-1, j=0; i!=-1; --i,  ++j ){
                    h[j].F = ((h[j-1].F*p.F%q.F)+s[i]+1)%q.F;
                    h[j].S = ((h[j-1].S*p.S%q.S)+s[i]+1)%q.S;
                }
            }
        }

        inline void get_pow(PII *h, const PII base, const int n, const PII P) {
            h[0].F=h[0].S=1;
            for(int i=1; i<=n; ++i) {
                h[i].F = (h[i-1].F*base.F)%P.F;
                h[i].S = (h[i-1].S*base.S)%P.S;
            }
        }

        inline int check(const int L, PII *h, PII *rh, PII const &pw, int n) {
            if(n>L) return -1;
            h++; rh++; //shift index
            UT temp1, temp2, temp3, temp4;//Lazy dog...
            for(int i=0; i+n-1<L; ++i) {
                temp1 = ((q.F - h[i-1].F*pw.F%q.F) + h[i+n-1].F)%q.F;
                temp2 = ((q.F - rh[L-i-n-1].F*pw.F%q.F) + rh[L-i-1].F)%q.F;
                temp3 = ((q.S - h[i-1].S*pw.S%q.S) + h[i+n-1].S)%q.S;
                temp4 = ((q.S - rh[L-i-n-1].S*pw.S%q.S) + rh[L-i-1].S)%q.S;
                /*
                for(int v=i; v<i+n; ++v) cout<<s[v];
                cout << endl;
                cout << temp1 << ' ';
                cout << temp2 << endl;
                cout << temp3 << ' ';
                cout << temp4 << endl;
                */
                if(temp1==temp2&&temp3==temp4) {
                    return i;
                }
            }
            return -1;
        }

};

int main(void) {
    Solution solver;
    string s;
    cin>>s;
    cout<<solver.longestPalindrome(s)<<endl;
    return 0;
}

接下來是 的版本, Manacher’s Algorithm 。

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
#include <bits/stdc++.h>
using namespace std;

class Solution {
    public:
        string preProcess(string &s) {
            if(s.empty()) return "^$";
            string res="^";
            for(string::size_type i=0; i!=s.length(); ++i) res+="#"+s.substr(i,1);
            return res+"#$";
        }

        string longestPalindrome(string &s) {
            string T=preProcess(s);
            int L = T.length();
            int *p = new int[T.length()];
            //fill(p, p+L, 0);
            int id=0, ix=0;
            for(int i=1; i<L-1; ++i) {
                p[i] = (i<ix)? min(p[(id<<1)-i], ix-i) : 0;
                while(T[i+p[i]+1]==T[i-p[i]-1]) ++p[i];
                if(i+p[i]>ix) { ix=i+p[i]; id=i; }
            }
            int offset=(int)(max_element(p+1,p+L-1)-p);
            int maxL=p[offset];
            delete[] p;
            return s.substr( (offset-1-maxL)>>1 , maxL);
        }
};

int main(void) {
    string s;
    Solution sol;
    cin>>s;
    cout<<sol.longestPalindrome(s)<<endl;
    return 0;
}
comments powered by Disqus