diff --git a/solution/0200-0299/0214.Shortest Palindrome/README.md b/solution/0200-0299/0214.Shortest Palindrome/README.md index d79f1e47c941f..ffd8c38adc83a 100644 --- a/solution/0200-0299/0214.Shortest Palindrome/README.md +++ b/solution/0200-0299/0214.Shortest Palindrome/README.md @@ -201,43 +201,193 @@ impl Solution { #### C# ```cs -// 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; - } +public class Solution { + public string ShortestPalindrome(string s) { + int baseValue = 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[i] - 'a' + 1; + prefix = (int)(((long)prefix * baseValue + t) % mod); + suffix = (int)((suffix + (long)t * mul) % mod); + mul = (int)(((long)mul * baseValue) % mod); + if (prefix == suffix) { + idx = i + 1; } - 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(); + } + + if (idx == n) { + return s; + } + + return new string(s.Substring(idx).Reverse().ToArray()) + s; + } +} +``` + + + + + + + +### 方法二:KMP 算法 + +根据题目描述,我们需要将字符串 $s$ 反转,得到字符串 $\textit{rev}$,然后求出字符串 $rev$ 的后缀与字符串 $s$ 的前缀的最长公共部分。我们可以使用 KMP 算法,将字符串 $s$ 与字符串 $rev$ 连接起来,求出其最长前缀与最长后缀的最长公共部分。 + +时间复杂度 $O(n)$,空间复杂度 $O(n)$。其中 $n$ 为字符串 $s$ 的长度。 + + + +#### Python3 + +```python +class Solution: + def shortestPalindrome(self, s: str) -> str: + t = s + "#" + s[::-1] + "$" + n = len(t) + next = [0] * n + next[0] = -1 + i, j = 2, 0 + while i < n: + if t[i - 1] == t[j]: + j += 1 + next[i] = j + i += 1 + elif j: + j = next[j] + else: + next[i] = 0 + i += 1 + return s[::-1][: -next[-1]] + s +``` + +#### Java + +```java +class Solution { + public String shortestPalindrome(String s) { + String rev = new StringBuilder(s).reverse().toString(); + char[] t = (s + "#" + rev + "$").toCharArray(); + int n = t.length; + int[] next = new int[n]; + next[0] = -1; + for (int i = 2, j = 0; i < n;) { + if (t[i - 1] == t[j]) { + next[i++] = ++j; + } else if (j > 0) { + j = next[j]; + } else { + next[i++] = 0; + } + } + return rev.substring(0, s.length() - next[n - 1]) + s; + } +} +``` + +#### C++ + +```cpp +class Solution { +public: + string shortestPalindrome(string s) { + string t = s + "#" + string(s.rbegin(), s.rend()) + "$"; + int n = t.size(); + int next[n]; + next[0] = -1; + next[1] = 0; + for (int i = 2, j = 0; i < n;) { + if (t[i - 1] == t[j]) { + next[i++] = ++j; + } else if (j > 0) { + j = next[j]; + } else { + next[i++] = 0; } } + return string(s.rbegin(), s.rbegin() + s.size() - next[n - 1]) + s; + } +}; +``` + +#### Go - return string.Empty; +```go +func shortestPalindrome(s string) string { + t := s + "#" + reverse(s) + "$" + n := len(t) + next := make([]int, n) + next[0] = -1 + for i, j := 2, 0; i < n; { + if t[i-1] == t[j] { + j++ + next[i] = j + i++ + } else if j > 0 { + j = next[j] + } else { + next[i] = 0 + i++ + } + } + return reverse(s)[:len(s)-next[n-1]] + s +} + +func reverse(s string) string { + t := []byte(s) + for i, j := 0, len(t)-1; i < j; i, j = i+1, j-1 { + t[i], t[j] = t[j], t[i] + } + return string(t) +} +``` + +#### TypeScript + +```ts +function shortestPalindrome(s: string): string { + const rev = s.split('').reverse().join(''); + const t = s + '#' + rev + '$'; + const n = t.length; + const next: number[] = Array(n).fill(0); + next[0] = -1; + for (let i = 2, j = 0; i < n; ) { + if (t[i - 1] === t[j]) { + next[i++] = ++j; + } else if (j > 0) { + j = next[j]; + } else { + next[i++] = 0; + } + } + return rev.slice(0, -next[n - 1]) + s; +} +``` + +#### C# + +```cs +public class Solution { + public string ShortestPalindrome(string s) { + char[] t = (s + "#" + new string(s.Reverse().ToArray()) + "$").ToCharArray(); + int n = t.Length; + int[] next = new int[n]; + next[0] = -1; + for (int i = 2, j = 0; i < n;) { + if (t[i - 1] == t[j]) { + next[i++] = ++j; + } else if (j > 0) { + j = next[j]; + } else { + next[i++] = 0; + } + } + return new string(s.Substring(next[n - 1]).Reverse().ToArray()).Substring(0, s.Length - next[n - 1]) + s; } } ``` diff --git a/solution/0200-0299/0214.Shortest Palindrome/README_EN.md b/solution/0200-0299/0214.Shortest Palindrome/README_EN.md index eb80912e1c16c..78c948e1285f2 100644 --- a/solution/0200-0299/0214.Shortest Palindrome/README_EN.md +++ b/solution/0200-0299/0214.Shortest Palindrome/README_EN.md @@ -182,43 +182,193 @@ impl Solution { #### C# ```cs -// 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; - } +public class Solution { + public string ShortestPalindrome(string s) { + int baseValue = 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[i] - 'a' + 1; + prefix = (int)(((long)prefix * baseValue + t) % mod); + suffix = (int)((suffix + (long)t * mul) % mod); + mul = (int)(((long)mul * baseValue) % mod); + if (prefix == suffix) { + idx = i + 1; } - 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(); + } + + if (idx == n) { + return s; + } + + return new string(s.Substring(idx).Reverse().ToArray()) + s; + } +} +``` + + + + + + + +### Solution 2: KMP Algorithm + +According to the problem description, we need to reverse the string $s$ to obtain the string $\textit{rev}$, and then find the longest common part of the suffix of the string $\textit{rev}$ and the prefix of the string $s$. We can use the KMP algorithm to concatenate the string $s$ and the string $\textit{rev}$ and find the longest common part of the longest prefix and the longest suffix. + +The time complexity is $O(n)$, and the space complexity is $O(n)$. Here, $n$ is the length of the string $s$. + + + +#### Python3 + +```python +class Solution: + def shortestPalindrome(self, s: str) -> str: + t = s + "#" + s[::-1] + "$" + n = len(t) + next = [0] * n + next[0] = -1 + i, j = 2, 0 + while i < n: + if t[i - 1] == t[j]: + j += 1 + next[i] = j + i += 1 + elif j: + j = next[j] + else: + next[i] = 0 + i += 1 + return s[::-1][: -next[-1]] + s +``` + +#### Java + +```java +class Solution { + public String shortestPalindrome(String s) { + String rev = new StringBuilder(s).reverse().toString(); + char[] t = (s + "#" + rev + "$").toCharArray(); + int n = t.length; + int[] next = new int[n]; + next[0] = -1; + for (int i = 2, j = 0; i < n;) { + if (t[i - 1] == t[j]) { + next[i++] = ++j; + } else if (j > 0) { + j = next[j]; + } else { + next[i++] = 0; + } + } + return rev.substring(0, s.length() - next[n - 1]) + s; + } +} +``` + +#### C++ + +```cpp +class Solution { +public: + string shortestPalindrome(string s) { + string t = s + "#" + string(s.rbegin(), s.rend()) + "$"; + int n = t.size(); + int next[n]; + next[0] = -1; + next[1] = 0; + for (int i = 2, j = 0; i < n;) { + if (t[i - 1] == t[j]) { + next[i++] = ++j; + } else if (j > 0) { + j = next[j]; + } else { + next[i++] = 0; } } + return string(s.rbegin(), s.rbegin() + s.size() - next[n - 1]) + s; + } +}; +``` + +#### Go - return string.Empty; +```go +func shortestPalindrome(s string) string { + t := s + "#" + reverse(s) + "$" + n := len(t) + next := make([]int, n) + next[0] = -1 + for i, j := 2, 0; i < n; { + if t[i-1] == t[j] { + j++ + next[i] = j + i++ + } else if j > 0 { + j = next[j] + } else { + next[i] = 0 + i++ + } + } + return reverse(s)[:len(s)-next[n-1]] + s +} + +func reverse(s string) string { + t := []byte(s) + for i, j := 0, len(t)-1; i < j; i, j = i+1, j-1 { + t[i], t[j] = t[j], t[i] + } + return string(t) +} +``` + +#### TypeScript + +```ts +function shortestPalindrome(s: string): string { + const rev = s.split('').reverse().join(''); + const t = s + '#' + rev + '$'; + const n = t.length; + const next: number[] = Array(n).fill(0); + next[0] = -1; + for (let i = 2, j = 0; i < n; ) { + if (t[i - 1] === t[j]) { + next[i++] = ++j; + } else if (j > 0) { + j = next[j]; + } else { + next[i++] = 0; + } + } + return rev.slice(0, -next[n - 1]) + s; +} +``` + +#### C# + +```cs +public class Solution { + public string ShortestPalindrome(string s) { + char[] t = (s + "#" + new string(s.Reverse().ToArray()) + "$").ToCharArray(); + int n = t.Length; + int[] next = new int[n]; + next[0] = -1; + for (int i = 2, j = 0; i < n;) { + if (t[i - 1] == t[j]) { + next[i++] = ++j; + } else if (j > 0) { + j = next[j]; + } else { + next[i++] = 0; + } + } + return new string(s.Substring(next[n - 1]).Reverse().ToArray()).Substring(0, s.Length - next[n - 1]) + s; } } ``` diff --git a/solution/0200-0299/0214.Shortest Palindrome/Solution.cs b/solution/0200-0299/0214.Shortest Palindrome/Solution.cs index c33ad4ae50914..d1b54e89b6a8d 100644 --- a/solution/0200-0299/0214.Shortest Palindrome/Solution.cs +++ b/solution/0200-0299/0214.Shortest Palindrome/Solution.cs @@ -1,39 +1,26 @@ -// https://leetcode.com/problems/shortest-palindrome/ +public class Solution { + public string ShortestPalindrome(string s) { + int baseValue = 131; + int mul = 1; + int mod = (int)1e9 + 7; + int prefix = 0, suffix = 0; + int idx = 0; + int n = s.Length; -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(); + for (int i = 0; i < n; ++i) { + int t = s[i] - 'a' + 1; + prefix = (int)(((long)prefix * baseValue + t) % mod); + suffix = (int)((suffix + (long)t * mul) % mod); + mul = (int)(((long)mul * baseValue) % mod); + if (prefix == suffix) { + idx = i + 1; } } - return string.Empty; + if (idx == n) { + return s; + } + + return new string(s.Substring(idx).Reverse().ToArray()) + s; } -} \ No newline at end of file +} diff --git a/solution/0200-0299/0214.Shortest Palindrome/Solution2.cpp b/solution/0200-0299/0214.Shortest Palindrome/Solution2.cpp new file mode 100644 index 0000000000000..6956b5693fc45 --- /dev/null +++ b/solution/0200-0299/0214.Shortest Palindrome/Solution2.cpp @@ -0,0 +1,20 @@ +class Solution { +public: + string shortestPalindrome(string s) { + string t = s + "#" + string(s.rbegin(), s.rend()) + "$"; + int n = t.size(); + int next[n]; + next[0] = -1; + next[1] = 0; + for (int i = 2, j = 0; i < n;) { + if (t[i - 1] == t[j]) { + next[i++] = ++j; + } else if (j > 0) { + j = next[j]; + } else { + next[i++] = 0; + } + } + return string(s.rbegin(), s.rbegin() + s.size() - next[n - 1]) + s; + } +}; diff --git a/solution/0200-0299/0214.Shortest Palindrome/Solution2.cs b/solution/0200-0299/0214.Shortest Palindrome/Solution2.cs new file mode 100644 index 0000000000000..067a74e88ad3c --- /dev/null +++ b/solution/0200-0299/0214.Shortest Palindrome/Solution2.cs @@ -0,0 +1,18 @@ +public class Solution { + public string ShortestPalindrome(string s) { + char[] t = (s + "#" + new string(s.Reverse().ToArray()) + "$").ToCharArray(); + int n = t.Length; + int[] next = new int[n]; + next[0] = -1; + for (int i = 2, j = 0; i < n;) { + if (t[i - 1] == t[j]) { + next[i++] = ++j; + } else if (j > 0) { + j = next[j]; + } else { + next[i++] = 0; + } + } + return new string(s.Substring(next[n - 1]).Reverse().ToArray()).Substring(0, s.Length - next[n - 1]) + s; + } +} diff --git a/solution/0200-0299/0214.Shortest Palindrome/Solution2.go b/solution/0200-0299/0214.Shortest Palindrome/Solution2.go new file mode 100644 index 0000000000000..a254925e173c9 --- /dev/null +++ b/solution/0200-0299/0214.Shortest Palindrome/Solution2.go @@ -0,0 +1,27 @@ +func shortestPalindrome(s string) string { + t := s + "#" + reverse(s) + "$" + n := len(t) + next := make([]int, n) + next[0] = -1 + for i, j := 2, 0; i < n; { + if t[i-1] == t[j] { + j++ + next[i] = j + i++ + } else if j > 0 { + j = next[j] + } else { + next[i] = 0 + i++ + } + } + return reverse(s)[:len(s)-next[n-1]] + s +} + +func reverse(s string) string { + t := []byte(s) + for i, j := 0, len(t)-1; i < j; i, j = i+1, j-1 { + t[i], t[j] = t[j], t[i] + } + return string(t) +} diff --git a/solution/0200-0299/0214.Shortest Palindrome/Solution2.java b/solution/0200-0299/0214.Shortest Palindrome/Solution2.java new file mode 100644 index 0000000000000..2e92823c7796c --- /dev/null +++ b/solution/0200-0299/0214.Shortest Palindrome/Solution2.java @@ -0,0 +1,19 @@ +class Solution { + public String shortestPalindrome(String s) { + String rev = new StringBuilder(s).reverse().toString(); + char[] t = (s + "#" + rev + "$").toCharArray(); + int n = t.length; + int[] next = new int[n]; + next[0] = -1; + for (int i = 2, j = 0; i < n;) { + if (t[i - 1] == t[j]) { + next[i++] = ++j; + } else if (j > 0) { + j = next[j]; + } else { + next[i++] = 0; + } + } + return rev.substring(0, s.length() - next[n - 1]) + s; + } +} diff --git a/solution/0200-0299/0214.Shortest Palindrome/Solution2.py b/solution/0200-0299/0214.Shortest Palindrome/Solution2.py new file mode 100644 index 0000000000000..7d538100384a2 --- /dev/null +++ b/solution/0200-0299/0214.Shortest Palindrome/Solution2.py @@ -0,0 +1,18 @@ +class Solution: + def shortestPalindrome(self, s: str) -> str: + t = s + "#" + s[::-1] + "$" + n = len(t) + next = [0] * n + next[0] = -1 + i, j = 2, 0 + while i < n: + if t[i - 1] == t[j]: + j += 1 + next[i] = j + i += 1 + elif j: + j = next[j] + else: + next[i] = 0 + i += 1 + return s[::-1][: -next[-1]] + s diff --git a/solution/0200-0299/0214.Shortest Palindrome/Solution2.ts b/solution/0200-0299/0214.Shortest Palindrome/Solution2.ts new file mode 100644 index 0000000000000..ba0dba154f53c --- /dev/null +++ b/solution/0200-0299/0214.Shortest Palindrome/Solution2.ts @@ -0,0 +1,17 @@ +function shortestPalindrome(s: string): string { + const rev = s.split('').reverse().join(''); + const t = s + '#' + rev + '$'; + const n = t.length; + const next: number[] = Array(n).fill(0); + next[0] = -1; + for (let i = 2, j = 0; i < n; ) { + if (t[i - 1] === t[j]) { + next[i++] = ++j; + } else if (j > 0) { + j = next[j]; + } else { + next[i++] = 0; + } + } + return rev.slice(0, -next[n - 1]) + s; +}