简体   繁体   English

如何使用递归计算字符串中的所有回文数?

[英]How to count all the palindromes in a string using recursion?

I have a recursive function that checks if a string is a palindrome, but my assignment asks me to count the number of palindromes in a string (for example kayak has 2).我有一个递归函数来检查字符串是否是回文,但我的作业要求我计算字符串中的回文数(例如 kayak 有 2 个)。

I'm really confused about how I can implement a recursive function that counts the number of palindromes.我真的很困惑如何实现一个计算回文数的递归函数。 Here's my current code:这是我当前的代码:

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;
  }
}

When the function gets a palindrome it is easy:当函数得到回文时,很容易:

  1. Record the input记录输入
  2. Try again without the edges没有边缘再试一次
  3. Stop when input is three characters or less当输入三个字符或更少时停止
"kayak" -> "aya"

If the input isn't a palindrome try "both ends" recursively eg with "kayam" try with both "kaya" and "ayam" and keep going...如果输入不是回文,请递归尝试“两端”,例如"kayam"尝试同时使用"kaya""ayam"并继续......

We stop the recursion when a string is 3 (or less) characters.当字符串为 3 个(或更少)字符时,我们停止递归。 A single character is not a palindrome and checking whether a two or three characters string is a palindrome is trivial.单个字符不是回文,检查两个或三个字符的字符串是否是回文是微不足道的。

                      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());

I think the accepted answer does not actually work.我认为接受的答案实际上不起作用。 It will not count palindromes unless they are centered in the string and will count substrings that are not palindromes if as long as they start and end with the same letter.它不会计算回文,除非它们在字符串中居中,并且只要它们以相同的字母开头和结尾,它就会计算不是回文的子串。 The answer from CertainPerformance would probably work but I think it would result in checking a lot of strings that don't need to be checked.来自CertainPerformance的答案可能会奏效,但我认为这会导致检查很多不需要检查的字符串。 Here's what I came up with, I think it works for the extra tests I've added.这是我想出的,我认为它适用于我添加的额外测试。

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

One method would be to first get all substrings , then validate each:一种方法是首先获取所有 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)) );

Here's an answer similar to that from CertainPerformance, but using recursion for the helper functions:这是一个类似于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 does just what you'd expect. getSubstrings所做的正是您所期望的。 getSubstrings('abcd') returns ["abcd", "abc", "ab", "a", "bcd", "bc", "b", "cd", "c", "d"] . getSubstrings('abcd')返回["abcd", "abc", "ab", "a", "bcd", "bc", "b", "cd", "c", "d"]

  • isPalindrome says that the empty string and single-character strings are automatically palindromes and that for another string we check that the two end characters match, recurring on the remainder. isPalindrome说空字符串和单字符字符串自动回文,对于另一个字符串,我们检查两个结束字符是否匹配,在剩余部分重复出现。

  • getPalindromicSubstrings finds all the substrings that are palindromes, skipping those of length 1 . getPalindromicSubstrings查找所有回文子字符串,跳过长度为1的子字符串。

  • countPalindromicSubstrings returns a count of those. countPalindromicSubstrings返回这些的计数。

  • countUniquePalindromicSubstrings uses a Set to filter out duplicates and returns that count. countUniquePalindromicSubstrings使用Set过滤掉重复项并返回该计数。

We could also easily write a getUniquePalindromicSubstrings in a similar manner if needed.如果需要,我们也可以以类似的方式轻松编写getUniquePalindromicSubstrings

getSubstrings is the only function with any complexity. getSubstrings是唯一具有任何复杂性的函数。 It operates by repeatedly slicing our string from to a value varying from length down to 1 , then recurring on the string starting with the second character, stopping when our input is empty.它通过重复将我们的字符串切片从length1的值进行切片,然后从第二个字符开始在字符串上重复出现,当我们的输入为空时停止。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM