如何在JavaScript中编写回文字符串

43

我想知道如何在javascript中编写回文程序,输入不同的单词后程序会显示该单词是否是回文。例如,单词“noon”是回文,而“bad”则不是。

提前感谢您。


27
通常要求别人编写检测回文的函数的目的是为了教授编程。如果让别人代劳,你就学不到任何东西。 - Ben
1
这个问题已经被问过并回答了几次 http://stackoverflow.com/a/20662606/437019 - Yossi Shasho
67个回答

68
function palindrome(str) {

    var len = str.length;
    var mid = Math.floor(len/2);

    for ( var i = 0; i < mid; i++ ) {
        if (str[i] !== str[len - 1 - i]) {
            return false;
        }
    }

    return true;
}

palindrome将根据布尔值(true/false)返回指定单词是否为回文。

更新:

由于性能问题,我在此问题上发布了悬赏,并进行了研究,以下是结果:

如果我们处理大量数据,例如

var abc = "asdhfkahkjdfhkaksjdfhaksdfjhakjddfhkjahksdhfaiuyqewiuryiquweyriyqiuweyriuqiuweryiquweyriuqyweirukajsdhfkahdfjkhakjsdhfkahksdhfakhdjkfqwiueryqiueyriuasdkfjhakjhdfkjashfkajhsdfkjahsdkalsdjflkasjdfljqoiweurasldjflasfdasdhfkahkjdfhkaksjdfhaksdfjhakjddfhkjahksdhfaiuyqewiuryiquweyriyqiuweyriuqiuweryiquweyriuqyweirukajsdhfkahdfjkhakjsdhfkahksdhfakhdjkfqwiueryqiueyriuasdkfjhakjhdfkjashfkajhsdfkjahsdkalsdjflkasjdfljqoiweurasldjflasfdasdhfkahkjdfhkaksjdfhaksdfjhakjddfhkjahksdhfaiuyqewiuryiquweyriyqiuweyriuqiuweryiquweyriuqyweirukajsdhfkahdfjkhakjsdhfkahksdhfakhdjkfqwiueryqiueyriuasdkfjhakjhdfkjashfkajhsdfkjahsdkalsdjflkasjdfljqoiweurasldjflasfdasdhfkahkjdfhkaksjdfhaksdfjhakjddfhkjahksdhfaiuyqewiuryiquweyriyqiuweyriuqiuweryiquweyriuqyweirukajsdhfkahdfjkhakjsdhfkahksdhfakhdjkfqwiueryqiueyriuasdkfjhakjhdfkjashfkajhsdfkjahsdkalsdjflkasjdfljqoiweurasldjflasfdasdhfkahkjdfhkaksjdfhaksdfjhakjddfhkjahksdhfaiuyqewiuryiquweyriyqiuweyriuqiuweryiquweyriuqyweirukajsdhfkahdfjkhakjsdhfkahksdhfakhdjkfqwiueryqiueyriuasdkfjhakjhdfkjashfkajhsdfkjahsdkalsdjflkasjdfljqoiweurasldjflasfdasdhfkahkjdfhkaksjdfhaksdfjhakjddfhkjahksdhfaiuyqewiuryiquweyriyqiuweyriuqiuweryiquweyriuqyweirukajsdhfkahdfjkhakjsdhfkahksdhfakhdjkfqwiueryqiueyriuasdkfjhakjhdfkjashfkajhsdfkjahsdkalsdjflkasjdfljqoiweurasldjflasfdasdhfkahkjdfhkaksjdfhaksdfjhakjddfhkjahksdhfaiuyqewiuryiquweyriyqiuweyriuqiuweryiquweyriuqyweirukajsdhfkahdfjkhakjsdhfkahksdhfakhdjkfqwiueryqiueyriuasdkfjhakjhdfkjashfkajhsdfkjahsdkalsdjflkasjdfljqoiweurasldjflasfdasdhfkahkjdfhkaksjdfhaksdfjhakjddfhkjahksdhfaiuyqewiuryiquweyriyqiuweyriuqiuweryiquweyriuqyweirukajsdhfkahdfjkhakjsdhfkahksdhfakhdjkfqwiueryqiueyriuasdkfjhakjhdfkjashfkajhsdfkjahsdkalsdjflkasjdfljqoiweurasldjflasfdasdhfkahkjdfhkaksjdfhaksdfjhakjddfhkjahksdhfaiuyqewiuryiquweyriyqiuweyriuqiuweryiquweyriuqyweirukajsdhfkahdfjkhakjsdhfkahksdhfakhdjkfqwiueryqiueyriuasdkfjhakjhdfkjashfkajhsdfkjahsdkalsdjflkasjdfljqoiweurasldjflasfdasdhfkahkjdfhkaksjdfhaksdfjhakjddfhkjahksdhfaiuyqewiuryiquweyriyqiuweyriuqiuweryiquweyriuqyweirukajsdhfkahdfjkhakjsdhfkahksdhfakhdjkfqwiueryqiueyriuasdkfjhakjhdfkjashfkajhsdfkjahsdkalsdjflkasjdfljqoiweurasldjflasfdasdhfkahkjdfhkaksjdfhaksdfjhakjddfhkjahksdhfaiuyqewiuryiquweyriyqiuweyriuqiuweryiquweyriuqyweirukajsdhfkahdfjkhakjsdhfkahksdhfakhdjkfqwiueryqiueyriuasdkfjhakjhdfkjashfkajhsdfkjahsdkalsdjflkasjdfljqoiweurasldjflasfdasdhfkahkjdfhkaksjdfhaksdfjhakjddfhkjahksdhfaiuyqewiuryiquweyriyqiuweyriuqiuweryiquweyriuqyweirukajsdhfkahdfjkhakjsdhfkahksdhfakhdjkfqwiueryqiueyriuasdkfjhakjhdfkjashfkajhsdfkjahsdkalsdjflkasjdfljqoiweurasldjflasfdasdhfkahkjdfhkaksjdfhaksdfjhakjddfhkjahksdhfaiuyqewiuryiquweyriyqiuweyriuqiuweryiquweyriuqyweirukajsdhfkahdfjkhakjsdhfkahksdhfakhdjkfqwiueryqiueyriuasdkfjhakjhdfkjashfkajhsdfkjahsdkalsdjflkasjdfljqoiweurasldjflasfdasdhfkahkjdfhkaksjdfhaksdfjhakjddfhkjahksdhfaiuyqewiuryiquweyriyqiuweyriuqiuweryiquweyriuqyweirukajsdhfkahdfjkhakjsdhfkahksdhfakhdjkfqwiueryqiueyriuasdkfjhakjhdfkjashfkajhsdfkjahsdkalsdjflkasjdfljqoiweurasldjflasfdasdhfkahkjdfhkaksjdfhaksdfjhakjddfhkjahksdhfaiuyqewiuryiquweyriyqiuweyriuqiuweryiquweyriuqyweirukajsdhfkahdfjkhakjsdhfkahksdhfakhdjkfqwiueryqiueyriuasdkfjhakjhdfkjashfkajhsdfkjahsdkalsdjflkasjdfljqoiweurasldjflasfdasdhfkahkjdfhkaksjdfhaksdfjhakjddfhkjahksdhfaiuyqewiuryiquweyriyqiuweyriuqiuweryiquweyriuqyweirukajsdhfkahdfjkhakjsdhfkahksdhfakhdjkfqwiueryqiueyriuasdkfjhakjhdfkjashfkajhsdfkjahsdkalsdjflkasjdfljqoiweurasldjflasfdasdhfkahkjdfhkaksjdfhaksdfjhakjddfhkjahksdhfaiuyqewiuryiquweyriyqiuweyriuqiuweryiquweyriuqyweirukajsdhfkahdfjkhakjsdhfkahksdhfakhdjkfqwiueryqiueyriuasdkfjhakjhdfkjashfkajhsdfkjahsdkalsdjflkasjdfljqoiweurasldjflasfdasdhfkahkjdfhkaksjdfhaksdfjhakjddfhkjahksdhfaiuyqewiuryiquweyriyqiuweyriuqiuweryiquweyriuqyweirukajsdhfkahdfjkhakjsdhfkahksdhfakhdjkfqwiueryqiueyriuasdkfjhakjhdfkjashfkajhsdfkjahsdkalsdjflkasjdfljqoiweurasldjflasfdasdhfkahkjdfhkaksjdfhaksdfjhakjddfhkjahksdhfaiuyqewiuryiquweyriyqiuweyriuqiuweryiquweyriuqyweirukajsdhfkahdfjkhakjsdhfkahksdhfakhdjkfqwiueryqiueyriuasdkfjhakjhdfkjashfkajhsdfkjahsdkalsdjflkasjdfljqoiweurasldjflasfdasdhfkahkjdfhkaksjdfhaksdfjhakjddfhkjahksdhfaiuyqewiuryiquweyriyqiuweyriuqiuweryiquweyriuqyweirukajsdhfkahdfjkhakjsdhfkahksdhfakhdjkfqwiueryqiueyriuasdkfjhakjhdfkjashfkajhsdfkjahsdkalsdjflkasjdfljqoiweurasldjflasfdasdhfkahkjdfhkaksjdfhaksdfjhakjddfhkjahksdhfaiuyqewiuryiquweyriyqiuweyriuqiuweryiquweyriuqyweirukajsdhfkahdfjkhakjsdhfkahksdhfakhdjkfqwiueryqiueyriuasdkfjhakjhdfkjashfkajhsdfkjahsdkalsdjflkasjdfljqoiweurasldjflasfd";

for ( var i = 0; i < 10; i++ ) {
    abc += abc;  // making string even more larger
}

function reverse(s) { // using this method for second half of string to be embedded
    return s.split("").reverse().join("");
}

abc += reverse(abc); // adding second half string to make string true palindrome

在这个例子中,回文序列是True,只是需要注意一下

贴出的回文函数在本例中花费了180到210毫秒的时间,而下面使用string == string.split('').reverse().join('')方法的函数则需要980到1010毫秒。

机器详情:

系统:Ubuntu 13.10 操作系统类型:32位 内存:2 Gb CPU:3.4 Ghz*2 浏览器:Firefox 27.0.1


2
还要注意,在您的第一个示例中,您只需要遍历字符串长度的一半。 - MrWhite
2
@crypticous 不,他的意思是你的回文函数在一半的时间内进行了冗余比较;在将前 str.length/2 个字符与后 str.length/2 个字符进行比较之后,你已经知道字符串是否为回文,因为你已经将前一半与后一半进行了比较。也就是说,你应该将 str.length 除以二,以获得完全相同的结果但速度提高一倍。 - Aleksi Torhamo
你可以将一半的长度存储在另一个变量中,以避免在每次迭代中重新计算它 var half = Math.floor(len/2); 然后在 for 循环中使用 for (var i = 0; i < half; i++) - Isaac Zepeda
如果您将字符串分成两个长度相等的部分,对其中一个进行反转,然后连接并与第一个字符串匹配,那么这应该比将整个字符串拆分、反转和重新连接更易读且更快。 - Swanidhi
真诚地问:为什么你需要在这里使用Math.floor?在什么情况下,字符串的长度不会返回一个整数? - Kyle Vassella
显示剩余4条评论

20

试试这个:

var isPalindrome = function (string) {
    if (string == string.split('').reverse().join('')) {
        alert(string + ' is palindrome.');
    }
    else {
        alert(string + ' is not palindrome.');
    }
}

document.getElementById('form_id').onsubmit = function() {
   isPalindrome(document.getElementById('your_input').value);
}

所以这个脚本会警报结果,判断输入的是否是回文。您需要将your_id更改为您的输入id,将form_id更改为您的表单id,以使其正常工作。

演示!


我在想这里使用的字符串反转方法是否存在潜在问题,因为JavaScript具有内部字符编码?我怀疑这对于英语回文可能不是问题,但是在其他语言中可能会更成问题。这只是需要注意的一些事情。stackoverflow.com/a/16776621/369434 - MrWhite
你说得没错,但我认为OP并不需要支持非字母字符,比如符号之类的。正如他所指出的例子“noon”一样。为什么你会想要支持符号呢? - aksu
我并不是特别考虑通用的“符号”,而是重点考虑带有重音的字母(例如á,é,í,ó,ú,ü,ñ等)以及其他非拉丁字母表 - 我不知道它们是否会成为问题。但是,确实只给出了英语示例。 - MrWhite
1
虽然这个解决方案简单/美观,但是对于更大的数据集,使用==.reverse()的组合是否比遍历一半的字符串长度慢? - theGreenCabbage
OP的帖子中没有提到性能问题。我的脚本只有在处理大量数据时才会稍微慢一点。当检查单词“noon”是否为回文时,这种缓慢并不明显。 - aksu
显示剩余3条评论

16

使用类似这样的东西

function isPalindrome(s) {
    return s === s.split("").reverse().join("") ? true : false;
}

alert(isPalindrome("noon"));

或者,根据 rightfold 的评论,可以优化上述代码,如下所示:

[已更新]

function isPalindrome(s) {
    return s === s.split("").reverse().join("");
}

alert(isPalindrome("malayalam")); 
alert(isPalindrome("english")); 

1
@rightfold 我认为它更冗长。你可以立即看到它将返回一个布尔值。 - James
比较 s == s^R 也存在双重努力的问题,例如回文字符串 s = uu^R,它会将 uu^R 与 (uu^R)^R = (u^R)^Ru^R = u^Ru 进行比较,而只需在中间拆分并将 u 与 u^R 进行比较即可。 - mvw

9

更快的方法:

- 在循环中计算一半的步长。

- 将单词长度存储在变量中而不是每次计算。

编辑: 像(mvw)指出的那样,将单词长度/2存储在临时变量中,以免在循环中每次计算。

function isPalindrome(word){
   var i,wLength = word.length-1,wLengthToCompare = wLength/2;

   for (i = 0; i <= wLengthToCompare ; i++) {
     if (word.charAt(i) != word.charAt(wLength-i)) {
        return false;
     }
   }
   return true;
} 

4
我很确定现代 JS 引擎可以优化掉 .length 访问。 - Bartek Banachewicz
+1 是遍历原始字符串长度的一半(其他答案似乎因某种原因忽略了这一点)。 - MrWhite
@BartekBanachewicz 您是正确的,'length'属性并不总是被计算,因此在某些浏览器上不会影响性能。然而,在某些浏览器上,将其缓存到变量中比在循环中访问'length'属性更快。 - Sai
@Sai 那么至少不应该声明它最终更快,但我看到你已经进行了编辑。 - Bartek Banachewicz
但是在循环的每次迭代中,您需要重新计算wLength/2 + 1和wLength-1。 - mvw

7

看看这个:

function isPalindrome(word){
    if(word==null || word.length==0){
        // up to you if you want true or false here, don't comment saying you 
        // would put true, I put this check here because of 
        // the following i < Math.ceil(word.length/2) && i< word.length
        return false;
    }
    var lastIndex=Math.ceil(word.length/2);
    for (var i = 0; i < lastIndex  && i< word.length; i++) {
        if (word[i] != word[word.length-1-i]) {
            return false;
        }
     }
     return true;
} 

编辑:现在只迭代了一半的单词以与单词的最后部分进行比较,因此只执行了一半的比较操作。对于大数据更快!!!

由于字符串是一个字符数组,所以不需要使用charAt函数!!!

参考:http://wiki.answers.com/Q/Javascript_code_for_palindrome


现在它只比较一半了...你不能再少了。 - piacente.cristian

7

让我们从回文的递归定义开始:

  1. 空字符串''是一个回文
  2. 由字符c组成的字符串'c'是回文
  3. 如果字符串s是回文,则对于某个字符c,字符串'c' + s + 'c'也是回文

这个定义可以直接编码为JavaScript:

function isPalindrome(s) {
  var len = s.length;
  // definition clauses 1. and 2.
  if (len < 2) {
    return true;
  }
  // note: len >= 2
  // definition clause 3.
  if (s[0] != s[len - 1]) {
    return false;
  }
  // note: string is of form s = 'a' + t + 'a'
  // note: s.length >= 2 implies t.length >= 0
  var t = s.substr(1, len - 2);
  return isPalindrome(t);
}

以下是一些与 MongoDB 的 mongo JavaScript shell 相关的额外测试代码,在带有调试器的 Web 浏览器中,将 print() 替换为 console.log()

function test(s) {
  print('isPalindrome(' + s + '): ' + isPalindrome(s));
}

test('');
test('a');
test('ab');
test('aa');
test('aab');
test('aba');
test('aaa');
test('abaa');
test('neilarmstronggnortsmralien');
test('neilarmstrongxgnortsmralien');
test('neilarmstrongxsortsmralien');

我得到了这个输出:
$ mongo palindrome.js
MongoDB shell version: 2.4.8
connecting to: test
isPalindrome(): true
isPalindrome(a): true
isPalindrome(ab): false
isPalindrome(aa): true
isPalindrome(aab): false
isPalindrome(aba): true
isPalindrome(aaa): true
isPalindrome(abaa): false
isPalindrome(neilarmstronggnortsmralien): true
isPalindrome(neilarmstrongxgnortsmralien): true
isPalindrome(neilarmstrongxsortsmralien): false

一种迭代解决方案是:

function isPalindrome(s) {
  var len = s.length;
  if (len < 2) {
    return true;
  }
  var i = 0;
  var j = len - 1;
  while (i < j) {
    if (s[i] != s[j]) {
      return false;
    }
    i += 1;
    j -= 1;
  }
  return true;
}

4

检查字符串是否是回文并考虑更多的条件,如大小写和特殊字符,最佳方法...

function checkPalindrom(str) {
    var str = str.replace(/[^a-zA-Z0-9]+/gi, '').toLowerCase();
    return str == str.split('').reverse().join('');
}

你可以使用以下单词和字符串进行测试,以获得更具体的结果。
1. bob
2. Doc, note, I dissent. A fast never prevents a fatness. I diet on cod

对于字符串,它会忽略特殊字符并将字符串转换为小写。

再次比较整个字符串而不是一半。 - mvw
请分享更多细节。为什么这是“最佳方式”? - Nico Haase

4
尝试一下。不过很难衡量表现。
function palin(word) {
    var i = 0,
        len = word.length - 1,
        max = word.length / 2 | 0;

    while (i < max) {
        if (word.charCodeAt(i) !== word.charCodeAt(len - i)) {
            return false;
        }
        i += 1;
    }
    return true;
}

我的想法是使用 charCodeAt() 而不是 charAt(),希望分配一个 Number 而不是一个 String 会有更好的性能,因为 String 是可变长度的,可能更复杂。此外,只遍历一半 (正如 Sai 所指出的那样),因为这就是所需的全部。另外,如果长度是奇数(例如: 'aba'),中间字符总是可以的。

值得注意的是使用 |0 进行整数转换。 - mvw

3

String.prototype.isPalindrome = function isPalindrome() {

    const cleanString = this.toLowerCase().replace(/\s+/g, '');
    const cleanStringRevers = cleanString.split("").reverse().join("");

    return cleanString === cleanStringRevers;
}

let nonPalindrome = 'not a palindrome';
let palindrome = 'sugus';

console.log(nonPalindrome.isPalindrome())

console.log(palindrome.isPalindrome())


2

以下是不使用String.reverse的一行代码:

const isPal = str => [...new Array(strLen = str.length)]
  .reduce((acc, s, i) => acc + str[strLen - (i + 1)], '') === str;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接