创建一个将字符串作为参数的函数。返回通过将字母添加到该字符串中而形成的最短回文。
"abc" // cbabc
"21234" // 4321234
"321234" // 4321234
"a" // a
到目前为止,我已经尝试过以下内容。
function isPal(str){
return [...str].reverse().join('') === str;
}
function palindrome(s){
if(isPal(s)) return s;
for(let i = 0;i<s.length;i++){
if(isPal(s)) return s;
s = s.slice(0,i) + s[s.length - 1 - i] + s.slice(i)
}
return s;
}
console.log(palindrome('abc'))
console.log(palindrome('321234'))
console.log(palindrome('21234'))
console.log(palindrome('a'))
该代码可以正常工作,但效率不高,因为它在每次迭代期间都检查isPal
。
我想知道这个问题的有效解决方案。我无法计算解决方案的时间复杂度,但它清除了非线性问题。我想知道线性复杂度或比我更好的解决方案。
答案 0 :(得分:4)
制作r = reversed string (s)
找到r
的最长后缀等于s
的前缀(逐字符检查字符)
a b c
c b a
for another example
2 1 2 3 4
4 3 2 1 2
but better variant does exist:
2 1 2 3 4
4 3 2 1 2
请注意,您真正不需要来构建反向字符串-只需使用相应的索引
两个操作都应该是线性的。
编辑:利用z-function
修改代码
(感谢@Kalido指向abcdba
测试用例)
可以使用先前主题中提到的z-functio n。我不熟悉JS(足够正确地生成结果字符串),所以只是制作了用于比较后缀为前缀为反的字符串后缀的z数组(请注意s[z[i]] == s[n - 1 - i - z[i]]
右边的索引修改)
代码查找除第一项外的最大值z[maxi]
。仅当第一项等于n(字符串已经是回文)时才使用第一项。结果是要添加的前缀长度。
例如,21234
给出z[maxi]=3
,因此函数返回2(我们添加长度为43212
的{{1}}前缀),即5-3=2
=> { {1}}
43
给出43 21234
,结果为零,因此我们不需要添加任何内容
cabac
给出z[0] = 5 = n
,因此我们在其他项目中选择最大值
abcdba
答案 1 :(得分:1)
您只需要检查一半的字符串就可以在isPal
函数上获得大量时间,或者如果检查失败了就返回:
function isPal(str){
for (let i = 0, l = str.length; i < l / 2; i++) {
if (str[i] != str[l-i-1]) {
return false
}
}
return true
}
console.log(isPal('kayak'))
console.log(isPal('toot'))
console.log(isPal('john'))
https://jsperf.com/palindrome-detection
注意:isPal
的复杂度保持线性,但最好的情况要好得多。