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.
For example:
Given "aacecaaa", return "aaacecaaa".
Given "abcd", return "dcbabcd".
/**
* @param {string} s
* @return {string}
*/
const reverseString = s => s.split('').reverse().join('');
const shortestPalindrome = s => {
const reverseStr = reverseString(s);
const combineStr = s + '#' + reverseStr;
const s_length = combineStr.length;
const next = [];
for(let i = 0; i < s_length; i++) {
next.push(0);
}
for(let i = 1; i < s_length; i++) {
let j = next[i - 1];
while(j > 0 && (combineStr[i] !== combineStr[j])) {
j = next[j - 1];
}
if(combineStr[i] === combineStr[j]) {
j++;
}
next[i] = j;
}
return reverseStr.substring(0, s.length - next[s_length - 1]) + s;
};
今天是第三天,也是主題 String
的最後一篇~
昨天練習了難度 Medium 的題目,今天當然要再進步一點,
所以今天寫的是難度 Hard 的題目 214. Shortest Palindrome!
題目是給一個字串,然後在字串前面加入字元,最後把這個字串變成一個最短回文字串。
如範例,abcd
-> dcbabcd
,在原本的字串 abcd
前面加上 dbc
,形成以 a
為中心的回文字串 dcb a bcd
這樣。
這題會用到第一天寫的反轉字串題,為什麼呢?
從上面 dcb a bcd
可以發現!
是不是很像 dcba
跟 abcd
黏在一起呢!!
dcba
跟 abcd
就剛好是反轉字串欸!!!
所以呢,這題其實就是考找出 dcba
的後綴 跟 abcd
的前綴的
最長匹配字串(a)!!
因為,答案就是.....
(反轉字串
- 最長匹配字串
) + 正常字串
= 最短回文字串
(dcba
- a
) + abcd
= dcbabcd
至於找前後綴的過程我使用 KMP演算法,這個演算法是用來搜尋一個小字串出現在大字串的位置,詳細教學可以參考這裡。
解題詳細步驟將在解題步驟中說明~
JavaScript ES6
的寫法請參考 Arrow Function。const reverseString = s => s.split('').reverse().join('');
步驟2.
我們主要計算的字串是組合過的字串 combindStr
,等於 反轉字串#正常字串
,中間的 #
是為了避免反轉字串跟正常字串混淆,也可以避掉正常字串是空字串的問題,需要注意的是區隔字元必須保證不會出現在正常字串中。
最下面的空陣列 next
是用來儲存 KMP演算法
中的 next[]
,next[]
詳細算法可以參考這裡,for
loop 把 next[]
先塞滿 0。
const reverseStr = reverseString(s);
const combineStr = s + '#' + reverseStr;
const s_length = combineStr.length;
const next = [];
for(let i = 0; i < s_length; i++) {
next.push(0);
}
next[]
,在此不多詳述,看這裡就非常清楚了~for(let i = 1; i < s_length; i++) {
let j = next[i - 1];
while(j > 0 && (combineStr[i] !== combineStr[j])) {
j = next[j - 1];
}
if(combineStr[i] === combineStr[j]) {
j++;
}
next[i] = j;
}
next[]
後,我們就知道他們的最長匹配字串長度了!我們在這用 JavaScript
原生的 substring()
提取反轉字串中從頭到最長匹配字串前的字串,然後再接上正常字串。return reverseStr.substring(0, s.length - next[s_length - 1]) + s;