Longest Palindromic Substring

2014.2.10 00:57

Given a string S, find the longest palindromic substring in S. You may assume that the maximum length of S is 1000, and there exists one unique longest palindromic substring.

Solution1:

  My first solution to this problem is the brute-force version, with O(n^2) time complexity, where n is the length of the string.

  The code needs no further explanation, please see for yourself.

  Time complexity is O(n^2), space complexity is O(1).

Accepted code:

 1 // 1AC, the brute-force solution, O(n^2) time complexity
 2 class Solution {
 3 public:
 4     string longestPalindrome(string s) {
 5         int i, j;
 6         int len;
 7         int ll, rr;
 8         string s1, s2;
 9         string str;
10         
11         len = (int)s.length();
12         if (len <= 1) {
13             return s;
14         }
15         s1 = "";
16         for (i = 0; i < len; ++i) {
17             j = 0;
18             while (true) {
19                 if ((i - j < 0) || (i + j > len - 1) || (s[i - j] != s[i + j])) {
20                     break;
21                 } else {
22                     ++j;
23                 }
24             }
25             --j;
26             if (2 * j + 1 > (int)s1.length()) {
27                 s1 = s.substr(i - j, 2 * j + 1);
28             }
29         }
30         s2 = "";
31         for (i = 0; i < len - 1; ++i) {
32             j = 0;
33             while (true) {
34                 if ((i - j < 0) || (i + 1 + j > len - 1) || (s[i - j] != s[i + 1 + j])) {
35                     break;
36                 } else {
37                     ++j;
38                 }
39             }
40             --j;
41             if (2 * j + 2 > (int)s2.length()) {
42                 s2 = s.substr(i - j, 2 * j + 2);
43             }
44         }
45         
46         if (s1.length() > s2.length()) {
47             return s1;
48         } else {
49             return s2;
50         }
51     }
52 };

Solution2:

  I believe you've heard about the Manacher's Algorithm. It is an efficient solution to this problem, which is linear and one-pass. Perhaps you haven't tried it yourself. Here is the wiki for your information: Manacher's Algorithm.

  The difference between Manacher's Algorithm and the Brute-Force one can be described with an example below:

    1. Here is a string "....sabcbas....", the part I show you here is a palindrome.

    2. 'c' is the center of that palindrome, and the two 's's are symmetric, with 'c' as the symmetric center.

    3. If this palindromic string is currently the longest we can find, and we're currently standing at the position of the second 's'.

    4. We see that "sabc" and "cbas" look symmetric, and we suppose that the longest palindrome you can get with the second 's' as the center might be similar to the first 's', since they're symmetric.

    5. Since the algorithm runs in one pass, we've know everything before s[i] when we're at position i.

    6. The right side of the first 's' is already known, so is the left side of the second 's'. No more matching is needed here. That's why this algorithm can save some duplicated matching.

    7. Nevertheless, the right part of "..." is still unknown, thus the matching must still be done here.

    8. If a longer palindrome is found, the center 'c' and the palindromic radius will be updated.

    9. The algorithm won't recalculate the palindrome within that longest palindromic range, that is, the farthest position the currently longest palindrome can reach. That's why the code has double loops, but still runs in O(n) time.

  You might find the descriptions above a total mess. I have to say it really wasn't easy for me to digest the code when learning this genius algorithm.

  The great Einstein once said, "if you can't explain it simply you don't understand it well enough". Guess that's why I tried to put a lot of words only to get you confused here. You might look at the code below, it's much simpler than my broken English. (^_^)

  Besides the algorithm description, there's one more thing to mention. To treat cases like "abba" and "aba", you don't have to write two copies of code, just insert some delimiter like '#' between every character will solve the problem.

  One last thing, this version of code put an extra character at the front, purely for the convenience of coding. If you've got your own way to make the code look short and clean, please share it with me.

  Time and space complexities are both O(n).

Accepted code:

 1 // 1CE, 2WA, 1AC, this really wasn't easy to understand..
 2 class Solution {
 3 public:
 4     string longestPalindrome(string s) {
 5         int len = (int)s.length();
 6         int nlen;
 7         int i, j;
 8         char *ss;
 9         int *p;
10         
11         nlen = 2 * len + 2;
12         ss = new char[nlen + 1];
13         p = new int[nlen + 1];
14         
15         // insert '#' between every character.
16         nlen = 0;
17         ss[nlen++] = '$';
18         for (i = 0; i < len; ++i) {
19             ss[nlen++] = '#';
20             ss[nlen++] = s[i];
21         }
22         ss[nlen++] = '#';
23         ss[nlen] = 0;
24         
25         // the farthest position the current palindromic string can reach.
26         int mx_pos;
27         // the index i that reaches this farthest position.
28         int id;
29         
30         // the Manacher algorithm
31         p[0] = 0;
32         mx_pos = 0;
33         for (i = 1; i < nlen; ++i) {
34             p[i] = 1;
35             if (mx_pos > i) {
36                 p[i] = p[2 * id - i];
37                 if (mx_pos - i < p[i]) {
38                     p[i] = mx_pos - i;
39                 }
40             }
41             
42             while (ss[i - p[i]] == ss[i + p[i]]) {
43                 ++p[i];
44             }
45             
46             if (i + p[i] > mx_pos) {
47                 mx_pos = i + p[i];
48                 id = i;
49             }
50         }
51         
52         // find the maximal value
53         int result = 0;
54         int ri;
55         string res_str;
56         char *res;
57         res = new char[len + 1];
58         for (i = 0; i < nlen; ++i) {
59             if (p[i] > result) {
60                 ri = i;
61                 result = p[i];
62             }
63         }
64         
65         len = 0;
66         for (i = ri - p[ri] + 1; i <= ri + p[ri] - 1; ++i) {
67             if ((i > 0) && ((i & 0x1) == 0)) {
68                 // odd positions are inserted with '#'
69                 // 0th position is inserted with '$'
70                 res[len++] = ss[i];
71             }
72         }
73         res[len] = 0;
74         res_str = string(res);
75         
76         delete [] res;
77         delete [] p;
78         delete [] ss;
79         
80         return res_str;
81     }
82 };

 

 posted on 2014-02-10 01:36  zhuli19901106  阅读(317)  评论(0编辑  收藏  举报