Given a string s, you are allowed to convert it to a palindrome by adding characters in front of it. Find and return the shortest palindrome you can find by performing this transformation.
Example 1:
Input:"aacecaaa"
Output:"aaacecaaa"
Example 2:
Input:"abcd"
Output:"dcbabcd"
最短回文串。给定一个字符串 s,你可以通过在字符串前面添加字符将其转换为回文串。找到并返回可以用这种方式转换的最短回文串。
这道题的最优解是马拉车算法,我这里给出two pointer的做法,代码运行速度慢一些。因为是找回文串,所以思路大概还是往two pointer上靠。所以一开始创建两个指针,在input的左右两端。如果两端的char一样,则往中间逼近,直到两个指针相遇,这是最理想的情况。如果一旦发现中间有两端char不一样的情况,因为只能在字符串的头部加新的字符,所以只能把左指针再放回开头,右指针放回end - 1的位置(舍弃最后一个char)再次比较。
worse case比如这个,aaaaabcaaaaa,因为每次end只挪动一位,所以当两个指针逼近到b和c的时候,end还是需要一步一步往左边移动,效率非常低。所以时间会接近于O(n^2)。
时间O(n^2) - worse case
空间O(1)
Java实现
1 class Solution { 2 public String shortestPalindrome(String s) { 3 int i = 0, end = s.length() - 1, j = end; 4 char chs[] = s.toCharArray(); 5 while (i < j) { 6 if (chs[i] == chs[j]) { 7 i++; 8 j--; 9 } else { 10 i = 0; 11 end--; 12 j = end; 13 } 14 } 15 return new StringBuilder(s.substring(end + 1)).reverse().toString() + s; 16 } 17 }
JavaScript实现
1 /** 2 * @param {string} s 3 * @return {string} 4 */ 5 var shortestPalindrome = function (s) { 6 let i = 0; 7 let j = s.length - 1; 8 let end = s.length - 1; 9 while (i < j) { 10 if (s.charAt(i) == s.charAt(j)) { 11 i++; 12 j--; 13 } else { 14 i = 0; 15 end--; 16 j = end; 17 } 18 } 19 return [...s.substring(end + 1)].reverse().join('') + s; 20 };
举个例子
input: abcd
双指针很显然没法逼近,因为一开始的a跟d就不一样,所以a再次跟c比较,跟b比较,都不行。根据代码,此时end在跳出while循环的时候,已经跟i一样,在a的位置了,所以bcd(end + 1)就会成为palindrome的一半,需要复制这个一半的reverse(dcb),再和s拼接在一起(dcb + abcd),组成最短的回文串dcbabcd。