引言
在算法与数据结构的学习之路上,我们经常会遇到关于字符串处理的经典问题。今天,让我们一起来探索一个有趣且常见的主题:回文句子(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)$,我们只使用了几个指针变量,没有开辟额外的线性空间。这在处理海量数据时优势非常明显。
总结
通过对"回文句子"问题的探讨,我们不仅掌握了双指针这一重要的算法技巧,还学会了如何处理带有噪声(如标点、空格)的脏数据。在实际的软件开发中,清洗数据是必不可少的一步,希望这个练习能帮助大家在未来的面试和工作中游刃有余。
快去动手尝试一下吧,让我们在代码的世界里感受对称之美!