Description:
Given a string s, find the longest palindrome substring in S. You can assume that the maximum length of S is 1000.
Example 1:
//Type: "babad" //Output: "bab" //Note: "aba" is also a valid answer.
Example 2:
//Input: "cbbd" //Output: "bb"
Solutions to problems
Solution 1 - central expansion method
Because of the symmetry of palindrome string, one number can be selected as the center each time to expand left and right to determine whether it is a palindrome string.
Since strings can be odd or even, you need to start expanding between 1 or 2 characters.
i + i - 1 expansion center.
Then i is the odd digit,
i + 1 is even digit.
Based on this theory, each cycle can be extended to both sides.
The time complexity of this solution is O(n^2).
The spatial complexity is O(1).
Solution 2 - horse drawn car algorithm
The first contact with this algorithm, but the person who came up with this algorithm, is really awesome.
The horse drawn cart algorithm improves the time complexity to linear.
This algorithm initially traverses characters and inserts a special symbol on both sides of each character. To avoid crossing the boundary, special labels are added at the beginning and the end, for example:
aabbcbbaa -> ^#a#a#b#b#c#b#b#a#a#$
Ensure that the current string must be an odd number.
Then expand left and right.
An array arr with the length of the original string is used to store the maximum number of center extensions.
(the subscript of each element of arr - arr[i]) / 2 is the subscript of the character of the original string.
If we set C as the center of the string and R as the length to the right of the string, then R = C + arr[i].
At this time, we can use the central expansion method to find.
We use j to represent the subscript corresponding to the i-th character and C.
But there are three situations that can lead to incorrect arr[j]
- Length exceeds R
- arr[j] to the left boundary of the original string
- When i is R
So in the above three cases, we need to use the central expansion method to do boundary treatment.
JS version
/** * @param {string} str * @param {number} left * @param {number} right * @return {number} */ const expandCenter = (str, left, right) => { while (left >= 0 && right < str.length && str[left] === str[right]) { left-- right++ } return str.slice(left + 1, right) } /** * @param {string} s * @return {string} */ const longestPalindrome1 = (s) => { if (!s || !s.length) { return '' } let result = '' for (let i = 0; i < s.length; i++) { const odd = expandCenter(s, i, i) const even = expandCenter(s, i, i + 1) if (odd.length > result.length) { result = odd } if (even.length > result.length) { result = even } } return result } /** * @param {string} s * @return {string} */ const setTarget = (s) => { if (!s) { return '' } if (s.length === 0) { return '^$' } let res = '^' for (let i = 0, len = s.length; i < len; ++i) { res = res + '#' + s.charAt(i) } res += '#$' return res } /** * @param {string} s * @return {string} */ const longestPalindrome2 = (s) => { let str = setTarget(s) let len = str.length let arr = new Array(len) let C = 0 // The center of the largest palindrome substring on the right boundary let R = 0 // Right boundary of substring for (let i = 1; i < len - 1; ++i) { let j = 2 * C - i if (R > i) { arr[i] = Math.min(R - i, arr[j]) // Right boundary processing } else { arr[i] = 0 } // In case of the above three special cases, the central expansion method is used while (str[i + 1 + arr[i]] === str[i - 1 - arr[i]]) { arr[i]++ } // Determine whether the value of R needs to be updated if (i + arr[i] + R) { C = i R = i + arr[i] } } let maxLen = 0 // Maximum length let index = 0 // Central subscript for (let i = 1; i < len - 1; ++i) { if (arr[i] > maxLen) { maxLen = arr[i] index = i } } let start = (index - maxLen) / 2 return s.substring(start, start + maxLen) }
TS version
/** * @Solution 1 * @thinking * Because of the symmetry of palindrome string, one number can be selected as the center each time to expand left and right to determine whether it is a palindrome string. * Since strings can be odd or even, you need to start expanding between 1 or 2 characters. * i + i - 1 expansion center. * And i is an odd number * i + 1 Even digit * Based on this theory, each cycle can be extended to both sides. * * The time complexity of this method is O(n^2) */ /** * @param {string} str * @param {number} left * @param {number} right * @return {number} */ const expandCenter = (str: string, left: number, right: number): string => { while (left >= 0 && right < str.length && str[left] === str[right]) { left-- right++ } return str.slice(left + 1, right) } /** * @param {string} s * @return {string} */ const longestPalindrome1 = (s: string): string => { if (!s || !s.length) { return '' } let result: string = '' for (let i: number = 0; i < s.length; i++) { const odd: string = expandCenter(s, i, i) const even: string = expandCenter(s, i, i + 1) if (odd.length > result.length) { result = odd } if (even.length > result.length) { result = even } } return result } const setTarget = (s: string): string => { if (!s) { return '' } if (s.length === 0) { return '^$' } let res: string = '^' for (let i: number = 0, len = s.length; i < len; ++i) { res = res + '#' + s.charAt(i) } res += '#$' return res } const longestPalindrome2 = (s: string): string => { let str: string = setTarget(s) let len: number = str.length let arr: number[] = new Array(len) let C: number = 0 // The center of the largest palindrome substring on the right boundary let R: number = 0 // Right boundary of substring for (let i: number = 1; i < len - 1; ++i) { let j: number = 2 * C - i if (R > i) { arr[i] = Math.min(R - i, arr[j]) // Right boundary processing } else { arr[i] = 0 } // In case of the above three special cases, the central expansion method is used while (str[i + 1 + arr[i]] == str[i - 1 - arr[i]]) { arr[i]++ } // Determine whether the value of R needs to be updated if (i + arr[i] + R) { C = i R = i + arr[i] } } let maxLen: number = 0 // Maximum length let index: number = 0 // Central subscript for (let i: number = 1; i < len - 1; ++i) { if (arr[i] > maxLen) { maxLen = arr[i] index = i } } let start: number = (index - maxLen) / 2 return s.substring(start, start + maxLen) }
PY version
from typing import List import math def expandCenter(s: str, left: int, right: int) -> str: while left >= 0 and right < len(s) and s[left] == s[right]: left -= 1 right += 1 return s[left + 1: right] def longestPalindrome1(s: str) -> str: if not(s) or not(len(s)): return '' result: str = '' for i in range(len(s)): odd: str = expandCenter(s, i, i) even: str = expandCenter(s, i, i + 1) if len(odd) > len(result): result = odd if len(even) > len(result): result = even return result def setTarget(s: str) -> str: if not(s): return '' if (len(s) == 0): return '^$' res: str = '^' for i in range(len(s)): res += '#' res += s[i] res += '#$' return res def longestPalindrome2(s: str) -> str: newStr: str = setTarget(s) l: int = len(newStr) arr = [0 for _ in range(l)] C: int = 0 R: int = 0 for i in range(l - 1): j: int = 2 * C - i if R > i: arr[i] = min(R - i, arr[j]) else: arr[i] = 0 while newStr[i + 1 + arr[i]] == newStr[i - 1 - arr[i]]: arr[i] += 1 if i + arr[i] + R: C = i R = i + arr[i] maxLen: int = 0 idx: int = 0 for i in range(1, l - 1): if arr[i] > maxLen: maxLen = int(arr[i]) idx = i start: int = int((idx - maxLen) / 2) return s[start:start + maxLen]
We have different ideas to leave a message!