Welcome to Subscribe On Youtube
Question
Formatted question description: https://leetcode.ca/all/214.html
You are given a string s
. You can convert s
to a palindrome by adding characters in front of it.
Return the shortest palindrome you can find by performing this transformation.
Example 1:
Input: s = "aacecaaa" Output: "aaacecaaa"
Example 2:
Input: s = "abcd" Output: "dcbabcd"
Constraints:
0 <= s.length <= 5 * 104
s
consists of lowercase English letters only.
Algorithm
- In the worst-case scenario, where there are no identical characters in the string
s
, the minimum number of characters required to be added iss.size() - 1
. - In the first example, the string contains a palindrome. To form a complete palindrome, only one character needs to be added to the front.
To solve this, first reverse the string s
to obtain t
. Then, compare the original string s
with the reversed string t
, starting from the first character and proceeding one character at a time:
- If they are equal, it indicates that
s
is already a palindrome. No additional characters need to be added, and the function can return immediately. - If they are not equal, remove the last character from
s
, remove the first character fromt
, and continue comparing. This process repeats until the strings are equal or the loop concludes.
This method ensures that the two strings are concatenated in the correct manner to form a palindrome.
Examples:
Worst Case: “abcda”+”adcba”
Reversed: a b c d a
s: a d c b a
Try to move both towards the center to find a possible overlap. By removing one character, we save an “a”.
Reversed: a b c d a
s: a d c b a
Move further, “da” and “ad” overlap, and the remaining part, “abc” vs “cba”, forms a palindrome.
Reversed: a b c d a
s: a d c b a
Therefore, “da” and “ad” go to the next recursion.
Reversed: d a
s: a d
Moving one more character aligns the strings perfectly, yielding the final result.
- “abc”+dfs()+”cba” => “abc”+”dad”+”cba”
Reversed: d a s: a d
Another Example: “aacecaaa”
- The iteration stops at the last ‘a’,
i=7
. "a"+dfs("aacecaa")+"a"
This approach strategically reduces the problem size by identifying overlapping parts between the original and reversed strings, effectively minimizing the number of characters needed to transform the input into a palindrome.
Code
-
public class Shortest_Palindrome { public class Solution { public String shortestPalindrome(String s) { if (s == null || s.length() == 0) { return ""; } int i = 0, n = s.length(); for (int j = n - 1; j >= 0; --j) { // @note: j will cross i, eg. making i=2 for "adcba" if (s.charAt(i) == s.charAt(j)) { ++i; } } // now [0, i) is a possible palindrome, but need extra check if (i == n) { return s; } String remaining = s.substring(i); // need to add reverse part of it String rem_rev = new StringBuilder(remaining).reverse().toString(); return rem_rev + shortestPalindrome(s.substring(0, i)) + remaining; } } } ############ class Solution { public String shortestPalindrome(String s) { int base = 131; int mul = 1; int mod = (int) 1e9 + 7; int prefix = 0, suffix = 0; int idx = 0; int n = s.length(); for (int i = 0; i < n; ++i) { int t = s.charAt(i) - 'a' + 1; prefix = (int) (((long) prefix * base + t) % mod); suffix = (int) ((suffix + (long) t * mul) % mod); mul = (int) (((long) mul * base) % mod); if (prefix == suffix) { idx = i + 1; } } if (idx == n) { return s; } return new StringBuilder(s.substring(idx)).reverse().toString() + s; } }
-
// OJ: https://leetcode.com/problems/shortest-palindrome/ // Time: O(N) // Space: O(1) ignoring the space taken by the answer class Solution { public: string shortestPalindrome(string s) { unsigned d = 16777619, h = 0, rh = 0, p = 1, maxLen = 0; for (int i = 0; i < s.size(); ++i) { h = h * d + s[i] - 'a'; rh += (s[i] - 'a') * p; p *= d; if (h == rh) maxLen = i + 1; } return string(rbegin(s), rbegin(s) + s.size() - maxLen) + s; } };
-
''' reversed(): returns a reverse iterator >>> s = "aabbcc" >>> reversed(s) <reversed object at 0x108384a60> >>> ''.join(reversed(s)) 'ccbbaa' >>> s = "aabbcc" >>> s[::-1] 'ccbbaa' ''' class Solution: def shortestPalindrome(self, s: str) -> str: if not s: return "" i, n = 0, len(s) for j in range(n - 1, -1, -1): if s[i] == s[j]: i += 1 if i == n: return s remaining = s[i:] rem_rev = remaining[::-1] return rem_rev + self.shortestPalindrome(s[:i]) + remaining ############ class Solution: def shortestPalindrome(self, s: str) -> str: base = 131 mod = 10**9 + 7 n = len(s) prefix = suffix = 0 mul = 1 idx = 0 for i, c in enumerate(s): prefix = (prefix * base + (ord(c) - ord('a') + 1)) % mod suffix = (suffix + (ord(c) - ord('a') + 1) * mul) % mod mul = (mul * base) % mod if prefix == suffix: idx = i + 1 return s if idx == n else s[idx:][::-1] + s ############ class Solution(object): # brutal force TLE def _shortestPalindrome(self, s): """ :type s: str :rtype: str """ def isPal(cand): start, end = 0, len(cand) - 1 while start < end: if cand[start] != cand[end]: return False start += 1 end -= 1 return True n = len(s) ans = s[::-1] + s ansLen = 2 * len(s) for i in reversed(range(0, len(s) + 1)): newPal = s[i:][::-1] + s if isPal(newPal) and n + len(s) - i < ansLen: ansLen = n + len(s) - i ans = newPal return ans def shortestPalindrome(self, s): r = s[::-1] for i in range(len(s) + 1): if s.startswith(r[i:]): return r[:i] + s
-
func shortestPalindrome(s string) string { n := len(s) base, mod := 131, int(1e9)+7 prefix, suffix, mul := 0, 0, 1 idx := 0 for i, c := range s { t := int(c-'a') + 1 prefix = (prefix*base + t) % mod suffix = (suffix + t*mul) % mod mul = (mul * base) % mod if prefix == suffix { idx = i + 1 } } if idx == n { return s } x := []byte(s[idx:]) for i, j := 0, len(x)-1; i < j; i, j = i+1, j-1 { x[i], x[j] = x[j], x[i] } return string(x) + s }
-
// https://leetcode.com/problems/shortest-palindrome/ using System.Text; public partial class Solution { public string ShortestPalindrome(string s) { for (var i = s.Length - 1; i >= 0; --i) { var k = i; var j = 0; while (j < k) { if (s[j] == s[k]) { ++j; --k; } else { break; } } if (j >= k) { var sb = new StringBuilder(s.Length * 2 - i - 1); for (var l = s.Length - 1; l >= i + 1; --l) { sb.Append(s[l]); } sb.Append(s); return sb.ToString(); } } return string.Empty; } }
-
impl Solution { pub fn shortest_palindrome(s: String) -> String { let base = 131; let (mut idx, mut prefix, mut suffix, mut mul) = (0, 0, 0, 1); for (i, c) in s.chars().enumerate() { let t = c as u64 - '0' as u64 + 1; prefix = prefix * base + t; suffix = suffix + t * mul; mul *= base; if prefix == suffix { idx = i + 1; } } if idx == s.len() { s } else { let x: String = (&s[idx..]).chars().rev().collect(); String::from(x + &s) } } }