zhangdizhangdi

125.验证回文串 🟩

题目

LeetCode 简单

题目

如果在将所有大写字符转换为小写字符、并移除所有非字母数字字符之后,短语正着读和反着读都一样。则可以认为该短语是一个 回文串
字母和数字都属于字母数字字符。

给你一个字符串 s,如果它是 回文串 ,返回 true ;否则,返回 false 。

示例:
输入: s = “A man, a plan, a canal: Panama”
输出:true
解释:“amanaplanacanalpanama” 是回文串。

输入:s = “race a car”
输出:false
解释:“raceacar” 不是回文串。

输入:s = " "
输出:true
解释:在移除非字母数字字符之后,s 是一个空字符串 “” 。
由于空字符串正着反着读都一样,所以是回文串。

题解

方法:正则 + 双指针

复杂度
  • 时间复杂度:O(N)

    s.toLowerCase():遍历整个字符串将其转换为小写,时间复杂度为 O(N)
    .match(/[a-z0-9]+/g):正则匹配引擎会扫描整个字符串以找出匹配的子串,时间复杂度为 O(N)
    s.join(‘’):将匹配到的数组拼接成一个新的字符串,由于总字符数不会超过 N,时间复杂度为 O(N)
    for 循环:双指针从两端向中间靠拢,最多执行 N/2 次,时间复杂度为 O(N)

  • 空间复杂度:O(N)

    s.toLowerCase() 会在内存中新建一个字符串,占用 O(N) 的空间(因为 JavaScript 中的字符串是不可变的)
    .match() 会生成一个包含多个子串的数组,占用额外的 O(N) 空间
    .join(‘’) 又会生成一个全新的字符串,再次占用 O(N) 的空间

js
function isPalindrome(s) {
    s = s.toLowerCase().match(/[a-z0-9]+/g)
    s = s ? s.join('') : ''
    for (let i = 0, j = s.length - 1; i < j; i++ , j--) {
        if (s[i] !== s[j]) {
            return false
        }
    }
    return true
}

const s = "A man, a plan, a canal: Panama"
console.log('🌰', isPalindrome(s))
执行结果
🌰 true

方法:双指针

复杂度
  • 时间复杂度:O(N)
  • 时间复杂度:O(1)
js
function isPalindrome(s) {
  let i = 0
  let j = s.length - 1

  // 辅助函数:判断字符是否是字母或数字
  const isValid = c => {
    return (
      (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9')
    )
  }

  while (i < j) {
    // 左指针跳过非法字符
    while (i < j && !isValid(s[i])) {
      i++
    }
    // 右指针跳过非法字符
    while (i < j && !isValid(s[j])) {
      j--
    }

    // 比较,注意统一转换为小写再比较
    if (s[i].toLowerCase() !== s[j].toLowerCase()) {
      return false
    }
    i++
    j--
  }

  return true
}

const s = 'race a car'
console.log('🌰', isPalindrome(s))
执行结果
🌰 false