【问题标题】:How to count all the palindromes in a string using recursion?如何使用递归计算字符串中的所有回文?
【发布时间】:2020-10-29 17:16:47
【问题描述】:

我有一个递归函数来检查一个字符串是否是回文,但我的作业要求我计算一个字符串中的回文数(例如 kayak 有 2 个)。

我真的很困惑如何实现一个计算回文数的递归函数。这是我当前的代码:

function isPalindrome(string) {
  if (string.length <= 1) {
    return true;
  }

  let [ firstLetter ] = string;
  let lastLetter = string[string.length - 1];

  if (firstLetter === lastLetter) {
    let stringWithoutFirstAndLastLetters = string.substring(1, string.length - 1);
    return isPalindrome(stringWithoutFirstAndLastLetters);
  } else {
    return false;
  }
}

【问题讨论】:

  • 这不是一个非常微不足道的问题。最简单的实现是遍历输入的所有可能的子字符串。也许有更聪明的东西。
  • 哦,好的,谢谢,你知道我该如何开始吗?
  • 我的大脑开始思考从索引 0-(n-1) 中寻找回文的过程。然后,从索引 1-(n-2) 中寻找回文,依此类推
  • 我不确定if (string.length &lt;= 1) { return true;。如果您希望计算长度为 1 的字符串,那么每个单独的字符也不应该匹配吗?也就是说,kayak 有 7 个结果,而不仅仅是 2 个结果?
  • 检查每个字母,左右扩展,检查字母是否保持不变(明显的细节,如偶数/奇数回文等......)

标签: javascript function recursion palindrome


【解决方案1】:

当函数得到回文时很容易:

  1. 记录输入
  2. 没有边缘再试一次
  3. 当输入少于三个字符时停止
"kayak" -> "aya"

如果输入不是回文,请递归尝试“两端”,例如使用"kayam" 尝试使用"kaya""ayam" 并继续...

当字符串为 3 个(或更少)字符时,我们停止递归。单个字符不是回文,检查两个或三个字符的字符串是否是回文是微不足道的。

                      kayam
                        |
                  +-------------+
                  |             |
                 kaya          ayam
                  |             |
              +-------+     +--------+
              |       |     |        |
             kay     aya   aya      yam

const reverse =
  ([...xs]) =>
    xs.reverse().join("");

const is_palindrome =
  a =>
      a.length === 1  ? false
    : a.length <= 3   ? a[0] === a[a.length-1]
                      : a === reverse(a);

const find_palindromes = str => {
  const scan =
    (x, xs = []) =>
        x.length <= 3     ? xs.concat(is_palindrome(x) ? x : [])
      : is_palindrome(x)  ? xs.concat
                              ( x
                              , scan(x.slice(1, -1))
                              )
                          : xs.concat
                              ( scan(x.slice(0, -1))
                              , scan(x.slice(1))
                              );

  return [...new Set(scan(str))];
};


console.log(find_palindromes("kayak").join());
console.log(find_palindromes("kayakkayak").join());
console.log(find_palindromes("kayakcanoe").join());
console.log(find_palindromes("kayam").join());
console.log(find_palindromes("appal").join());
console.log(find_palindromes("madamimadam").join());
console.log(find_palindromes("madamimadamkayak").join());

【讨论】:

  • 将单字母字符串计为回文似乎有点精神分裂,而不是单词中的单字母。我真的无法判断这是否是要求。无论如何,这是一个不错的版本。
  • 好吧,我想我说得太早了。我刚刚尝试了"madamimadam" 并按预期得到了5,但是当我将"kayak" 附加到它时,我得到了0。在末尾添加字符绝对不应该减少回文子串的数量。
  • @customcommander 这不算回文吗?它只是将它们打印出来
  • @ScottSauyet 我正在寻找类似于 chelmertz 的答案
  • @28space_junkiee 是的,但计算结果应该不会太难 ;)
【解决方案2】:

我认为接受的答案实际上不起作用。它不会计算回文,除非它们位于字符串的中心,并且只要它们以相同的字母开头和结尾,它就会计算不是回文的子字符串。来自CertainPerformance 的答案可能会起作用,但我认为这会导致检查很多不需要检查的字符串。这是我想出的,我认为它适用于我添加的额外测试。

function countPalindromes(string) {
    if (string.length <= 1) {
    return 0;
    }

    count = 0

    for ( var i = 0; i < string.length; i++  ) {
    count += countPalindromesCenteredAt(string, i)
    count += countPalindromesCenteredAfter(string, i)
    }

    return count
}

function countPalindromesCenteredAt(string, i) {
    count = 0
    for ( var j = 1; i-j>=0 && i+j < string.length; j++  ) {
    if (string.charAt(i-j) === string.charAt(i+j)) {
        count += 1
    }
    else {
        return count
    }
    }

    return count
}

function countPalindromesCenteredAfter(string, i) {
    count = 0
    
    for ( var j = 1; i-j>=0 && i+j < string.length; j++  ) {
    if (string.charAt(i-j+1) === string.charAt(i+j)) {
        count += 1
    }
    else {
        return count
    }
    }

    return count
}

console.log(countPalindromes("kayak"));
console.log(countPalindromes("aya"));
console.log(countPalindromes("kayakcanoe"));
console.log(countPalindromes("kcanoek"));

【讨论】:

  • 谢谢你的澄清是的,我也注意到了,但我不是在寻找那个,因为我的老师只是想提出一个回文数并计算回文数。我将选择回文,所以它很可能会很短,只是为了节省时间并让事情变得简单。我接受了您的回答,因为我知道它可以帮助其他人,所以谢谢!
  • 您原来的作业陈述:“计算一个字符串中的回文数”肯定需要解释。字符串“kayam”中的回文数是多少? “皮划艇”呢?在这一点上这是学术性的,但您最初的问题也是如此。 :)
  • 您知道我如何将其实现为迭代吗? @biomiker
  • 你知道我如何将其用作迭代吗?
  • @28space_junkiee 我的理解是已经迭代了。
【解决方案3】:

一种方法是首先get all substrings,然后验证每个:

getAllSubstrings('kayak').filter(str => str.length >= 2 && isPalindrome(str))

function getAllSubstrings(str) {
  var i, j, result = [];

  for (i = 0; i < str.length; i++) {
      for (j = i + 1; j < str.length + 1; j++) {
          result.push(str.slice(i, j));
      }
  }
  return result;
}
function isPalindrome(string) {
  if (string.length <= 1) {
    return true;
  }

  let [ firstLetter ] = string;
  let lastLetter = string[string.length - 1];

  if (firstLetter === lastLetter) {
    let stringWithoutFirstAndLastLetters = string.substring(1, string.length - 1);
    return isPalindrome(stringWithoutFirstAndLastLetters);
  } else {
    return false;
  }
}
console.log(
  getAllSubstrings('kayak').filter(str => str.length >= 2 && isPalindrome(str))
);

【讨论】:

    【解决方案4】:

    这里有一个类似于来自CertainPerformance 的答案,但对辅助函数使用递归:

    const getSubstrings = (str) =>
      str .length == 0 
        ? []
        : [
            ... str .split ('') .map ((_, i) => str .slice (0, str .length - i)),
            ... getSubstrings (str .slice (1))
          ]
    
    const isPalindrome = (str) =>
      str .length < 2
        ? true
        : str [0] === str .slice (-1) [0] && isPalindrome (str .slice (1, -1))
    
    const getPalindromicSubstrings = (str) =>
      getSubstrings (str) 
        .filter (s => s.length > 1) 
        .filter (isPalindrome)
    
    const countPalindromicSubstrings = (str) =>
      getPalindromicSubstrings (str) .length
    
    const countUniquePalindromicSubstrings = (str) =>
      new Set(getPalindromicSubstrings (str)) .size
    
    console .log (getPalindromicSubstrings ('madamimadam'))
    console .log (countPalindromicSubstrings ('madamimadam'))
    console .log (countUniquePalindromicSubstrings ('madamimadam'))
    .as-console-wrapper {max-height: 100% !important; top: 0}
    • getSubstrings 符合您的预期。 getSubstrings('abcd') 返回["abcd", "abc", "ab", "a", "bcd", "bc", "b", "cd", "c", "d"]

    • isPalindrome 表示空字符串和单字符串自动回文,对于另一个字符串,我们检查两个结束字符是否匹配,并在其余部分重复出现。

    • getPalindromicSubstrings 查找所有回文子串,跳过长度为 1 的子串。

    • countPalindromicSubstrings 返回其中的计数。

    • countUniquePalindromicSubstrings 使用 Set 过滤掉重复项并返回该计数。

    如果需要,我们也可以以类似的方式轻松编写getUniquePalindromicSubstrings

    getSubstrings 是唯一具有任何复杂性的函数。它通过重复将我们的字符串从length1 的值重复切片来操作,然后从第二个字符开始在字符串上循环,当我们的输入为空时停止。

    【讨论】:

    • 有没有办法简化这个答案类似于 chelmertz 的答案
    • @28space_junkiee:我不确定我是否理解。您对 chelmertz 的回答发表评论说这是不正确的,然后在这个答案上要求我让它更像那个答案。唔?我认为这个分解很简单。一个函数获取子字符串,另一个函数测试回文,第三个函数查找所有回文子字符串,另外两个函数中的任何一个返回它们的计数,具体取决于您的要求。授予非递归回文检查可能更简单(const isPalindrome = (str) =&gt; str.split('').reverse().join('') == str),但您特别要求递归。
    猜你喜欢
    • 1970-01-01
    • 2012-10-04
    • 2013-11-15
    • 2020-03-15
    • 1970-01-01
    • 2019-09-01
    • 2013-07-21
    • 1970-01-01
    • 2015-08-12
    相关资源
    最近更新 更多