跳转至

BM88 判断是否为回文字符串

入门通过率 59.34%python3核心代码模式样例通过牛客 AC字符串

牛客原题  源码

讲解章节:字符串处理

一句话

首尾两个指针相向而行,逐对比较到相遇。

解题思路

这题考什么

把「正着读和倒着读一样」这句定义翻译成可判定的形式: 对每个下标 i 都要有 s[i] == s[n-1-i]。这 n 条约束里, 第 i 条与第 n-1-i 条完全等价,所以只需要检查前一半, 两个指针相向而行,到相遇为止:

a b s b a
^       ^   "a" == "a",两指针内收
  ^   ^     "b" == "b"
    ^       相遇,全程没出现分歧 -> 是回文

奇数长度时正中间那个字符要与自己比,l < r 的条件让它被自动跳过,无需特判。 这是双指针里最基础的一种形态,见 双指针与滑动窗口。

数据规模与复杂度

0 < n <= 1e6、仅含小写字母,时限「其他语言 2 秒」,题面要求空间 O(1)。 双指针最多比较 n/2 对,时间 O(n)、空间 O(1)——全程只有两个下标。 str == str[::-1] 一行也对,但它要额外拷贝一份长度为 n 的字符串(空间 O(n)), 不满足题面的空间要求;而且必须先把整串反转出来才能比, 双指针遇到第一处不匹配就能提前返回。

坑在哪

  1. 循环条件用 l < r:两指针相遇即可停手。写成 l <= r 答案不变, 只是多做一次「中间字符与自己比」的无用比较;但写成 l != r 就是灾难—— 偶数长度时两指针会擦肩而过(l 从 r-1 直接跳到 r+1),条件永远为真, 指针继续外移直到下标越界。
  2. 右指针的起点是 len - 1 而不是 len,这个减一就是「末位下标」与「长度」的差; 写成 len 会在第一次取值时越界。
  3. 参数名 str 遮蔽了内置的 str 类型,这是牛客模板自带的,签名不能改; 实现里因此不能再用 str(...) 做类型转换——那会变成对形参这个字符串发起调用。
  4. 不匹配时要立即返回 False,不能只记个标志继续扫:提前退出正是双指针 相对切片反转的唯一优势,最坏情况两者都是 O(n),但最好情况这里只比一次。

参考实现

solutions/nowcoder/BM88/sol.py
from typing import List, Optional


class Solution:
    def judge(self, str: str) -> bool:
        # 左指针从首位、右指针从末位(下标 len-1,不是 len)相向而行
        l, r = 0, len(str) - 1
        # 条件是 l < r:相遇即停,中间那个字符不必与自己比
        while l < r:
            # 出现任何一对不相等即可定案,不必扫完整串
            if str[l] != str[r]:
                return False
            l += 1
            r -= 1
        # 前半段全部对上,说明整串对称
        return True
[:octicons-arrow-left-16: BM87](BM87.md) [BM89 :octicons-arrow-right-16:](BM89.md)