如何使弦回文?

时间:2019-04-29 06:40:18

标签: javascript string algorithm

创建一个将字符串作为参数的函数。返回通过将字母添加到该字符串中而形成的最短回文。

"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。 我想知道这个问题的有效解决方案。我无法计算解决方案的时间复杂度,但它清除了非线性问题。我想知道线性复杂度或比我更好的解决方案。

2 个答案:

答案 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的复杂度保持线性,但最好的情况要好得多。