javascript 递归中的切片问题
Issue with slicing in javascript recursion
各位!我知道这不是递归的最佳可能基本情况,而且我知道它有缺陷。但是,在处理它时,我意识到有几次它跳过了对数组第一个元素的切片,最终 returning false
而不是 true
。
我可能遗漏了什么,但我很想知道为什么会这样?
PS。如果这个问题的措辞不够完美,我深表歉意,但我希望代码能给你一些更好的想法。
代码:
function palindrome(string) {
let str = string.replace(/[^A-Za-z0-9]/g, '')
console.log( str )
str = str.split("")
if (str.length === 3 && str[0] === str[2] || str.length === 1) {
return true
} else if (str.length === 2 && str[0] !== str[1]) {
return false
} else {
return palindrome(string.slice(1, -1))
}
return false
}
console.log(palindrome("Anne I vote more cars race Rome to Vienna"))
与return值:
['A', 'n', 'n', 'a', 'I', 'v', 'o', 't', 'e', 'm', 'o', 'r', 'e', 'c', 'a', 'r', 's', 'r', 'a', 'c', 'e', 'R', 'o', 'm', 'e', 't', 'o', 'V', 'i', 'e', 'n', 'n', 'a']
['n', 'n', 'a', 'I', 'v', 'o', 't', 'e', 'm', 'o', 'r', 'e', 'c', 'a', 'r', 's', 'r', 'a', 'c', 'e', 'R', 'o', 'm', 'e', 't', 'o', 'V', 'i', 'e', 'n', 'n']
['n', 'a', 'I', 'v', 'o', 't', 'e', 'm', 'o', 'r', 'e', 'c', 'a', 'r', 's', 'r', 'a', 'c', 'e', 'R', 'o', 'm', 'e', 't', 'o', 'V', 'i', 'e', 'n']
['a', 'I', 'v', 'o', 't', 'e', 'm', 'o', 'r', 'e', 'c', 'a', 'r', 's', 'r', 'a', 'c', 'e', 'R', 'o', 'm', 'e', 't', 'o', 'V', 'i', 'e']
['I', 'v', 'o', 't', 'e', 'm', 'o', 'r', 'e', 'c', 'a', 'r', 's', 'r', 'a', 'c', 'e', 'R', 'o', 'm', 'e', 't', 'o', 'V', 'i']
['I', 'v', 'o', 't', 'e', 'm', 'o', 'r', 'e', 'c', 'a', 'r', 's', 'r', 'a', 'c', 'e', 'R', 'o', 'm', 'e', 't', 'o', 'V']
['I', 'v', 'o', 't', 'e', 'm', 'o', 'r', 'e', 'c', 'a', 'r', 's', 'r', 'a', 'c', 'e', 'R', 'o', 'm', 'e', 't', 'o']
['v', 'o', 't', 'e', 'm', 'o', 'r', 'e', 'c', 'a', 'r', 's', 'r', 'a', 'c', 'e', 'R', 'o', 'm', 'e', 't', 'o']
['v', 'o', 't', 'e', 'm', 'o', 'r', 'e', 'c', 'a', 'r', 's', 'r', 'a', 'c', 'e', 'R', 'o', 'm', 'e', 't']
['o', 't', 'e', 'm', 'o', 'r', 'e', 'c', 'a', 'r', 's', 'r', 'a', 'c', 'e', 'R', 'o', 'm', 'e']
['t', 'e', 'm', 'o', 'r', 'e', 'c', 'a', 'r', 's', 'r', 'a', 'c', 'e', 'R', 'o', 'm', 'e']
['e', 'm', 'o', 'r', 'e', 'c', 'a', 'r', 's', 'r', 'a', 'c', 'e', 'R', 'o', 'm']
['m', 'o', 'r', 'e', 'c', 'a', 'r', 's', 'r', 'a', 'c', 'e', 'R', 'o']
['m', 'o', 'r', 'e', 'c', 'a', 'r', 's', 'r', 'a', 'c', 'e', 'R']
['o', 'r', 'e', 'c', 'a', 'r', 's', 'r', 'a', 'c', 'e']
['r', 'e', 'c', 'a', 'r', 's', 'r', 'a', 'c', 'e']
['e', 'c', 'a', 'r', 's', 'r', 'a', 'c']
['c', 'a', 'r', 's', 'r', 'a']
['c', 'a', 'r', 's', 'r']
['a', 'r', 's']
['r', 's']
false
您在错误的元素上执行了 .slice(1, -1)
,因为它保留了空格,而这些空格在回文中不匹配。
而您的代码只测试中间的最后一个字母,而忘记周围的所有其他字母。
我宁愿这样看代码
console.log(palindrome("Anne I vote more cars race Rome to Vienna"))
function palindrome( str )
{
return recussiv( str.replace(/[^A-Za-z0-9]/g, '').toLowerCase() )
function recussiv(s)
{
console.log('-->', s )
if (s.length > 1)
{
return (s[0] === s[s.length-1]) ? recussiv(s.slice(1, -1)) : false
}
else return true
}
}
.as-console-wrapper { max-height: 100% !important; top: 0
实施问题
恐怕此实现至少存在三个不同的问题。
首先,它忘记了对字符进行相同大小写处理,'Anne'
中的首字母大写 'A'
与 [=20= 中的最终小写 'a'
不匹配].
其次,它正确地改变了 string
输入以删除非字母数字字符,但是当它再次出现时,它是在这个原始的 string
而不是新的 str
.
第三,也是最根本的一点,它在重现之前不检查最重要的事实:它不测试第一个字符是否与最后一个字符匹配。
开始使用初始版本
我们可以修复所有这些问题并获得如下所示的版本:
function palindrome(string) {
let str = string.replace(/[^A-Za-z0-9]/g, '') .toLowerCase ().split("") // Issue 1 -- case
// console.log( str.join('') )
if (str.length === 3 && str[0] === str[2] || str.length === 1) {
return true
} else if (str.length === 2 && str[0] !== str[1]) { // Issue 3 -- compare first and last
return false
} else if (str [0] !== str [str .length - 1]) {
return false
} else {
return palindrome(str.slice(1, -1).join('')) // Issue 2 -- recur on correct item
}
return false
}
console .log (palindrome ("Anne I vote more cars race Rome to Vienna")) //=> true
console .log (palindrome ("Anne I vote more cars X race Rome to Vienna")) //=> false
console .log (palindrome ("A man, a plan, a canal: Panama!")) //=> true
console .log (palindrome ("A man, a plan, a banal palindrome.")) //=> false
遗留问题
但即使在这里,也有一些真正的丑陋之处。我们在每次调用时在字符串和数组之间来回转换。我们 运行 在每次调用时清理字符串,当它在第一次调用后不需要时。而且它包含比真正需要的更多的独立案例。
不要继续转换
第一个修复是微不足道的。我们这里根本不需要数组。我们可以对字符串进行所有测试。字符串中的字符可以完全像数组项一样进行索引,并且它们具有等效的 length
属性.
只初始化一次
第二个问题,重新运行每次调用的初始化通常通过以下两种方式之一解决:添加初始调用时默认的额外参数,或添加辅助函数。我们将选择后者,因为前者存在一些真正的潜在问题(尽管它通常仍然值得考虑。)这分为两种风格。我们可以将辅助函数嵌套在主函数中,然后从内部调用它。或者我们可以使它成为我们刚刚调用的外部函数。 MisterJoJo 的回答恰如其分地展示了第一种风格,所以我们可以看看第二种风格。在这里,我们可以编写一个内部递归 _isPalindrome
函数,它接受一串小写字母数字字符和 returns 一个布尔值。然后我们可以编写一个 public 包装函数来接受任何字符串,通过删除所有非字母数字字符并将其小写来对其进行规范化,将结果传递给该内部函数并返回其结果。它可能看起来像这样1:
const isPalindrome = (string) =>
_isPalindrome (string .replace (/\W/g, '') .toLowerCase())
const _isPalindrome = (cs) => /* ... recursive version here ... */
现在JS模块好用的时代,可以把那个内部函数封装在模块里,只留下main函数public可见
处理更少的案件
对于第三期,我们需要真正了解什么是回文。从根本上说,它只是意味着字符串向前和向后读取相同。这个答案代表的直觉是,这意味着第一个和最后一个字符相同,并且它们之间的剩余字符串也是回文。
对于递归函数,我们至少需要一个基本情况。我们什么时候可以不再检查第一个字符和最后一个字符是否相同?答案很清楚:当我们没有分开的第一个和最后一个字符时。2。所以我们的基本情况是字符串中有零个或一个字符。单字符字符串显然是回文。零字符字符串也是如此;如果这听起来很奇怪,请查找 vacuous truths。所以我们现在有一个简单的基本情况和一个简单的递归情况,我们可以编写我们的函数:
const isPalindrome = (string) =>
_isPalindrome (string .replace (/\W/g, '') .toLowerCase ())
const _isPalindrome = (cs) =>
cs .length < 2
? true
: cs [0] == cs [cs .length - 1] && _isPalindrome (cs .slice (1, -1))
console .log (isPalindrome ("Anne I vote more cars race Rome to Vienna")) //=> true
console .log (isPalindrome ("Anne I vote more cars X race Rome to Vienna")) //=> false
console .log (isPalindrome ("A man, a plan, a canal: Panama!")) //=> true
console .log (isPalindrome ("A man, a plan, a banal palindrome.")) //=> false
使用实用函数
我们可以轻松地在这里停下来。但是该代码中仍然存在一些丑陋之处。所有索引操作都需要一些阅读才能理解。有一个强有力的论据将这种丑陋转移到命名良好的辅助函数中。我通常在助手 last
和 first
3 周围放置,而且写一个 middle
也很容易。这些获取字符串或数组的第一个或最后一个字符,或者对于 middle
,获取第一个和最后一个字符之间的所有字符。使用它们可以使我们的主要功能更具可读性:
const first = (xs) => xs [0]
const last = (xs) => xs [xs .length - 1]
const middle = (xs) => xs .slice (1, -1)
const isPalindrome = (string) =>
_isPalindrome (string .replace (/\W/g, '') .toLowerCase ())
const _isPalindrome = (cs) =>
cs .length < 2
? true
: first (cs) == last (cs) && _isPalindrome (middle (cs))
通用处理
我们不小心写了一个比我们试图写的更通用的函数版本!请注意,我们可以在数组上使用相同的内部函数:
_isPalindrome (['foo', 'bar', 'qux', 'bar', 'foo']) //=> true
_isPalindrome (['foo', 'bar', 'qux', 'foo']) //=> false
语义很简单。如果数组的元素少于两个,或者如果第一个和最后一个元素相同且其余元素形成回文,则数组是回文。
这主要是一个愉快的意外。当我注意到它时,我将最初编写的参数名称 letters
更改为更通用的 cs
,这可能会让人想起 characters
但并不坚持。
注意到此实现的通用性质,我可能会更改 middle
以便我们可以将其用于更多类型,任何有限的可迭代类型。 middle
现在不会处理这个,因为并非所有此类可迭代对象都有 slice
方法。但是都是4可以转换成数组,然后我们就可以使用数组slice
的方法
这里是对 middle
的简单更新,使该函数更加通用:
const middle = (xs) => [...xs] .slice (1, -1)
正如我所说,这是一个快乐的意外。我在写代码的时候没有注意到它,只是在输入这个 post.
简单多了isPalindrome
最后,问题指出这个问题可能不是用递归解决的最佳方法。这是千真万确的。我们之前对它进行了掩饰,但确实提到如果字符串正向和反向读取相同,则它是回文。我们可以直接这样写:
const isPalindrome = (string) =>
_isPalindrome (string .replace (/\W/g, '') .toLowerCase ())
const _isPalindrome = (s) =>
s == s .split ('') .reverse () .join ('')
console .log (isPalindrome ("Anne I vote more cars race Rome to Vienna")) //=> true
console .log (isPalindrome ("Anne I vote more cars X race Rome to Vienna")) //=> false
console .log (isPalindrome ("A man, a plan, a canal: Panama!")) //=> true
console .log (isPalindrome ("A man, a plan, a banal palindrome.")) //=> false
虽然 String
没有 reverse
方法,但我们可以轻松地转换为数组,反转数组,并将结果连接回字符串。然后我们简单测试一下反转后的字符串是否和原来的一样。5
这个版本不像上一个那样通用,但它绝对是将回文的想法直接转化为代码的更直接的翻译。
1 请注意,正则表达式 /\W/g
正好等同于 /[^A-Za-z0-9]/g
。它是 \w
的反义词,表示 [a-zA-z0-9]
,但输入起来更简单。
2我们还可以注意到,如果第一个和最后一个字符是相同的,也就是说,如果我们的字符串只有一个字符长,我们可以使用相同的过程。所有会改变的是我们测试的长度是小于 2
还是小于 1
.
3 first
通常被称为 head
,原因不值得在这里讨论。
4 嗯,又是有限的
5 出于与上面 first
和 last
相同的原因,可能值得从中提取一个 reverseString
辅助函数。这是一个真正可重用的简单函数。这留作练习。
各位!我知道这不是递归的最佳可能基本情况,而且我知道它有缺陷。但是,在处理它时,我意识到有几次它跳过了对数组第一个元素的切片,最终 returning false
而不是 true
。
我可能遗漏了什么,但我很想知道为什么会这样?
PS。如果这个问题的措辞不够完美,我深表歉意,但我希望代码能给你一些更好的想法。
代码:
function palindrome(string) {
let str = string.replace(/[^A-Za-z0-9]/g, '')
console.log( str )
str = str.split("")
if (str.length === 3 && str[0] === str[2] || str.length === 1) {
return true
} else if (str.length === 2 && str[0] !== str[1]) {
return false
} else {
return palindrome(string.slice(1, -1))
}
return false
}
console.log(palindrome("Anne I vote more cars race Rome to Vienna"))
与return值:
['A', 'n', 'n', 'a', 'I', 'v', 'o', 't', 'e', 'm', 'o', 'r', 'e', 'c', 'a', 'r', 's', 'r', 'a', 'c', 'e', 'R', 'o', 'm', 'e', 't', 'o', 'V', 'i', 'e', 'n', 'n', 'a']
['n', 'n', 'a', 'I', 'v', 'o', 't', 'e', 'm', 'o', 'r', 'e', 'c', 'a', 'r', 's', 'r', 'a', 'c', 'e', 'R', 'o', 'm', 'e', 't', 'o', 'V', 'i', 'e', 'n', 'n']
['n', 'a', 'I', 'v', 'o', 't', 'e', 'm', 'o', 'r', 'e', 'c', 'a', 'r', 's', 'r', 'a', 'c', 'e', 'R', 'o', 'm', 'e', 't', 'o', 'V', 'i', 'e', 'n']
['a', 'I', 'v', 'o', 't', 'e', 'm', 'o', 'r', 'e', 'c', 'a', 'r', 's', 'r', 'a', 'c', 'e', 'R', 'o', 'm', 'e', 't', 'o', 'V', 'i', 'e']
['I', 'v', 'o', 't', 'e', 'm', 'o', 'r', 'e', 'c', 'a', 'r', 's', 'r', 'a', 'c', 'e', 'R', 'o', 'm', 'e', 't', 'o', 'V', 'i']
['I', 'v', 'o', 't', 'e', 'm', 'o', 'r', 'e', 'c', 'a', 'r', 's', 'r', 'a', 'c', 'e', 'R', 'o', 'm', 'e', 't', 'o', 'V']
['I', 'v', 'o', 't', 'e', 'm', 'o', 'r', 'e', 'c', 'a', 'r', 's', 'r', 'a', 'c', 'e', 'R', 'o', 'm', 'e', 't', 'o']
['v', 'o', 't', 'e', 'm', 'o', 'r', 'e', 'c', 'a', 'r', 's', 'r', 'a', 'c', 'e', 'R', 'o', 'm', 'e', 't', 'o']
['v', 'o', 't', 'e', 'm', 'o', 'r', 'e', 'c', 'a', 'r', 's', 'r', 'a', 'c', 'e', 'R', 'o', 'm', 'e', 't']
['o', 't', 'e', 'm', 'o', 'r', 'e', 'c', 'a', 'r', 's', 'r', 'a', 'c', 'e', 'R', 'o', 'm', 'e']
['t', 'e', 'm', 'o', 'r', 'e', 'c', 'a', 'r', 's', 'r', 'a', 'c', 'e', 'R', 'o', 'm', 'e']
['e', 'm', 'o', 'r', 'e', 'c', 'a', 'r', 's', 'r', 'a', 'c', 'e', 'R', 'o', 'm']
['m', 'o', 'r', 'e', 'c', 'a', 'r', 's', 'r', 'a', 'c', 'e', 'R', 'o']
['m', 'o', 'r', 'e', 'c', 'a', 'r', 's', 'r', 'a', 'c', 'e', 'R']
['o', 'r', 'e', 'c', 'a', 'r', 's', 'r', 'a', 'c', 'e']
['r', 'e', 'c', 'a', 'r', 's', 'r', 'a', 'c', 'e']
['e', 'c', 'a', 'r', 's', 'r', 'a', 'c']
['c', 'a', 'r', 's', 'r', 'a']
['c', 'a', 'r', 's', 'r']
['a', 'r', 's']
['r', 's']
false
您在错误的元素上执行了 .slice(1, -1)
,因为它保留了空格,而这些空格在回文中不匹配。
而您的代码只测试中间的最后一个字母,而忘记周围的所有其他字母。
我宁愿这样看代码
console.log(palindrome("Anne I vote more cars race Rome to Vienna"))
function palindrome( str )
{
return recussiv( str.replace(/[^A-Za-z0-9]/g, '').toLowerCase() )
function recussiv(s)
{
console.log('-->', s )
if (s.length > 1)
{
return (s[0] === s[s.length-1]) ? recussiv(s.slice(1, -1)) : false
}
else return true
}
}
.as-console-wrapper { max-height: 100% !important; top: 0
实施问题
恐怕此实现至少存在三个不同的问题。
首先,它忘记了对字符进行相同大小写处理,'Anne'
中的首字母大写 'A'
与 [=20= 中的最终小写 'a'
不匹配].
其次,它正确地改变了 string
输入以删除非字母数字字符,但是当它再次出现时,它是在这个原始的 string
而不是新的 str
.
第三,也是最根本的一点,它在重现之前不检查最重要的事实:它不测试第一个字符是否与最后一个字符匹配。
开始使用初始版本
我们可以修复所有这些问题并获得如下所示的版本:
function palindrome(string) {
let str = string.replace(/[^A-Za-z0-9]/g, '') .toLowerCase ().split("") // Issue 1 -- case
// console.log( str.join('') )
if (str.length === 3 && str[0] === str[2] || str.length === 1) {
return true
} else if (str.length === 2 && str[0] !== str[1]) { // Issue 3 -- compare first and last
return false
} else if (str [0] !== str [str .length - 1]) {
return false
} else {
return palindrome(str.slice(1, -1).join('')) // Issue 2 -- recur on correct item
}
return false
}
console .log (palindrome ("Anne I vote more cars race Rome to Vienna")) //=> true
console .log (palindrome ("Anne I vote more cars X race Rome to Vienna")) //=> false
console .log (palindrome ("A man, a plan, a canal: Panama!")) //=> true
console .log (palindrome ("A man, a plan, a banal palindrome.")) //=> false
遗留问题
但即使在这里,也有一些真正的丑陋之处。我们在每次调用时在字符串和数组之间来回转换。我们 运行 在每次调用时清理字符串,当它在第一次调用后不需要时。而且它包含比真正需要的更多的独立案例。
不要继续转换
第一个修复是微不足道的。我们这里根本不需要数组。我们可以对字符串进行所有测试。字符串中的字符可以完全像数组项一样进行索引,并且它们具有等效的 length
属性.
只初始化一次
第二个问题,重新运行每次调用的初始化通常通过以下两种方式之一解决:添加初始调用时默认的额外参数,或添加辅助函数。我们将选择后者,因为前者存在一些真正的潜在问题(尽管它通常仍然值得考虑。)这分为两种风格。我们可以将辅助函数嵌套在主函数中,然后从内部调用它。或者我们可以使它成为我们刚刚调用的外部函数。 MisterJoJo 的回答恰如其分地展示了第一种风格,所以我们可以看看第二种风格。在这里,我们可以编写一个内部递归 _isPalindrome
函数,它接受一串小写字母数字字符和 returns 一个布尔值。然后我们可以编写一个 public 包装函数来接受任何字符串,通过删除所有非字母数字字符并将其小写来对其进行规范化,将结果传递给该内部函数并返回其结果。它可能看起来像这样1:
const isPalindrome = (string) =>
_isPalindrome (string .replace (/\W/g, '') .toLowerCase())
const _isPalindrome = (cs) => /* ... recursive version here ... */
现在JS模块好用的时代,可以把那个内部函数封装在模块里,只留下main函数public可见
处理更少的案件
对于第三期,我们需要真正了解什么是回文。从根本上说,它只是意味着字符串向前和向后读取相同。这个答案代表的直觉是,这意味着第一个和最后一个字符相同,并且它们之间的剩余字符串也是回文。
对于递归函数,我们至少需要一个基本情况。我们什么时候可以不再检查第一个字符和最后一个字符是否相同?答案很清楚:当我们没有分开的第一个和最后一个字符时。2。所以我们的基本情况是字符串中有零个或一个字符。单字符字符串显然是回文。零字符字符串也是如此;如果这听起来很奇怪,请查找 vacuous truths。所以我们现在有一个简单的基本情况和一个简单的递归情况,我们可以编写我们的函数:
const isPalindrome = (string) =>
_isPalindrome (string .replace (/\W/g, '') .toLowerCase ())
const _isPalindrome = (cs) =>
cs .length < 2
? true
: cs [0] == cs [cs .length - 1] && _isPalindrome (cs .slice (1, -1))
console .log (isPalindrome ("Anne I vote more cars race Rome to Vienna")) //=> true
console .log (isPalindrome ("Anne I vote more cars X race Rome to Vienna")) //=> false
console .log (isPalindrome ("A man, a plan, a canal: Panama!")) //=> true
console .log (isPalindrome ("A man, a plan, a banal palindrome.")) //=> false
使用实用函数
我们可以轻松地在这里停下来。但是该代码中仍然存在一些丑陋之处。所有索引操作都需要一些阅读才能理解。有一个强有力的论据将这种丑陋转移到命名良好的辅助函数中。我通常在助手 last
和 first
3 周围放置,而且写一个 middle
也很容易。这些获取字符串或数组的第一个或最后一个字符,或者对于 middle
,获取第一个和最后一个字符之间的所有字符。使用它们可以使我们的主要功能更具可读性:
const first = (xs) => xs [0]
const last = (xs) => xs [xs .length - 1]
const middle = (xs) => xs .slice (1, -1)
const isPalindrome = (string) =>
_isPalindrome (string .replace (/\W/g, '') .toLowerCase ())
const _isPalindrome = (cs) =>
cs .length < 2
? true
: first (cs) == last (cs) && _isPalindrome (middle (cs))
通用处理
我们不小心写了一个比我们试图写的更通用的函数版本!请注意,我们可以在数组上使用相同的内部函数:
_isPalindrome (['foo', 'bar', 'qux', 'bar', 'foo']) //=> true
_isPalindrome (['foo', 'bar', 'qux', 'foo']) //=> false
语义很简单。如果数组的元素少于两个,或者如果第一个和最后一个元素相同且其余元素形成回文,则数组是回文。
这主要是一个愉快的意外。当我注意到它时,我将最初编写的参数名称 letters
更改为更通用的 cs
,这可能会让人想起 characters
但并不坚持。
注意到此实现的通用性质,我可能会更改 middle
以便我们可以将其用于更多类型,任何有限的可迭代类型。 middle
现在不会处理这个,因为并非所有此类可迭代对象都有 slice
方法。但是都是4可以转换成数组,然后我们就可以使用数组slice
的方法
这里是对 middle
的简单更新,使该函数更加通用:
const middle = (xs) => [...xs] .slice (1, -1)
正如我所说,这是一个快乐的意外。我在写代码的时候没有注意到它,只是在输入这个 post.
简单多了isPalindrome
最后,问题指出这个问题可能不是用递归解决的最佳方法。这是千真万确的。我们之前对它进行了掩饰,但确实提到如果字符串正向和反向读取相同,则它是回文。我们可以直接这样写:
const isPalindrome = (string) =>
_isPalindrome (string .replace (/\W/g, '') .toLowerCase ())
const _isPalindrome = (s) =>
s == s .split ('') .reverse () .join ('')
console .log (isPalindrome ("Anne I vote more cars race Rome to Vienna")) //=> true
console .log (isPalindrome ("Anne I vote more cars X race Rome to Vienna")) //=> false
console .log (isPalindrome ("A man, a plan, a canal: Panama!")) //=> true
console .log (isPalindrome ("A man, a plan, a banal palindrome.")) //=> false
虽然 String
没有 reverse
方法,但我们可以轻松地转换为数组,反转数组,并将结果连接回字符串。然后我们简单测试一下反转后的字符串是否和原来的一样。5
这个版本不像上一个那样通用,但它绝对是将回文的想法直接转化为代码的更直接的翻译。
1 请注意,正则表达式 /\W/g
正好等同于 /[^A-Za-z0-9]/g
。它是 \w
的反义词,表示 [a-zA-z0-9]
,但输入起来更简单。
2我们还可以注意到,如果第一个和最后一个字符是相同的,也就是说,如果我们的字符串只有一个字符长,我们可以使用相同的过程。所有会改变的是我们测试的长度是小于 2
还是小于 1
.
3 first
通常被称为 head
,原因不值得在这里讨论。
4 嗯,又是有限的
5 出于与上面 first
和 last
相同的原因,可能值得从中提取一个 reverseString
辅助函数。这是一个真正可重用的简单函数。这留作练习。