回文句子 | 练习题

引言

在算法与数据结构的学习之路上,我们经常会遇到关于字符串处理的经典问题。今天,让我们一起来探索一个有趣且常见的主题:回文句子(Palindrome Sentence)。

回文不仅仅是单词层面的(如 "madam"),它还可以扩展到整个句子。在这个练习中,我们将一起深入研究如何判断一个句子是否是回文,并在这个过程中掌握字符串处理的一些核心技巧。

什么是回文句子?

在正式开始编码之前,让我们先明确一下定义。

通常,回文是指正读和反读都相同的字符串。而在句子回文的场景下,规则通常更加灵活:

  • 我们需要忽略句子中的空格
  • 我们需要忽略标点符号
  • 我们通常忽略大小写的差异。

示例分析

让我们看几个例子来直观地理解:

  • "A man, a plan, a canal: Panama"

* 如果我们只考虑字母数字字符,并将其转换为统一的小写形式,这个句子会变成:"amanaplanacanalpanama"。

* 反转后依然是:"amanaplanacanalpanama"。

* 结论:这是一个回文句子。

  • "race a car"

* 去除空格和符号,并统一大小写后:"raceacar"。

* 反转后为:"racacecar"。

* 结论:这不是一个回文句子。

解题思路与算法

为了判断一个句子是否为回文,我们可以采取以下策略。

方法一:过滤与反转(直观但空间复杂度较高)

这是最直接的思路,让我们来看看步骤:

  • 清洗数据:遍历原始字符串,构建一个新的字符串。在这个过程中,我们只保留字母和数字,并忽略大小写(通常全部转为小写)。
  • 反转比对:将清洗后的字符串进行反转,然后判断它是否与清洗后的原字符串相等。

代码逻辑示例:

def isPalindrome(s: str) -> bool:
    # 第一步:清洗字符串
    cleaned = ‘‘
    for char in s:
        if char.isalnum():  # 检查是否为字母或数字
            cleaned += char.lower()
    
    # 第二步:反转并比较
    return cleaned == cleaned[::-1]

虽然这种方法很容易理解,但它需要额外的 $O(N)$ 空间来存储 cleaned 字符串。让我们看看能不能优化它。

方法二:双指针法(推荐,空间复杂度 O(1))

作为追求极致的工程师,我们更倾向于使用双指针法。这种方法不需要创建新的字符串,因此空间复杂度是常数级别的。

核心思路:

  • 初始化两个指针,INLINECODE1d15c1d6 指向字符串的开头,INLINECODE1d137967 指向字符串的末尾。
  • 在 INLINECODE6b91bea1 小于 INLINECODEb1304391 的条件下循环:

* 如果 INLINECODE09cf6779 指向的字符不是字母或数字,则向右移动 INLINECODE9043b2a4(忽略无效字符)。

* 如果 INLINECODE2d4c6045 指向的字符不是字母或数字,则向左移动 INLINECODE649f5bb6(忽略无效字符)。

* 如果两者都是有效字符,我们比较它们(忽略大小写)。如果不相等,直接返回 False

* 如果相等,INLINECODE2a06d391 向右移,INLINECODE7e8ef640 向左移,继续下一轮比较。

  • 如果循环顺利结束,说明所有对应位置的字符都匹配,返回 True

代码逻辑示例:

def isPalindrome(s: str) -> bool:
    left, right = 0, len(s) - 1
    
    while left < right:
        # 如果 left 指针不是字母或数字,跳过
        if not s[left].isalnum():
            left += 1
            continue
        
        # 如果 right 指针不是字母或数字,跳过
        if not s[right].isalnum():
            right -= 1
            continue
            
        # 比较两个字符(统一转为小写)
        if s[left].lower() != s[right].lower():
            return False
            
        # 移动指针
        left += 1
        right -= 1
        
    return True

复杂度分析

让我们对这两种方法做一个简单的总结:

  • 时间复杂度:$O(N)$。无论是哪种方法,我们本质上都需要遍历字符串中的所有字符一次。这里 $N$ 是字符串的长度。
  • 空间复杂度

* 方法一:$O(N)$,因为我们需要额外的空间存储清洗后的字符串。

* 方法二:$O(1)$,我们只使用了几个指针变量,没有开辟额外的线性空间。这在处理海量数据时优势非常明显。

总结

通过对"回文句子"问题的探讨,我们不仅掌握了双指针这一重要的算法技巧,还学会了如何处理带有噪声(如标点、空格)的脏数据。在实际的软件开发中,清洗数据是必不可少的一步,希望这个练习能帮助大家在未来的面试和工作中游刃有余。

快去动手尝试一下吧,让我们在代码的世界里感受对称之美!

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。如需转载,请注明文章出处豆丁博客和来源网址。https://shluqu.cn/22439.html
点赞
0.00 平均评分 (0% 分数) - 0