LeetCode:判断字符串是否回文(Palindrome Number)

本文详细介绍了如何判断一个整数是否为回文数的算法实现,通过具体示例和代码片段,深入剖析了回文数判断的核心逻辑,包括特殊情况下(如负数和末位为0的情况)的处理策略。

8.判断字符串是否回文(Palindrome Number)

例子1:

  • Input: 121
  • Output: true

例子 2:

  • Input: -121
  • Output: false

说明:从左到右,它显示为-121。 从右到左,它变成121-。 因此它不是回文。

例子3:

  • Input: 10
  • Output: false

说明:从右到左读取01。 因此它不是回文。

 class PalindromeNumber
    {
            public bool IsPalindrome(int x)
            {
                if (x < 0 || (x % 10 == 0 && x != 0))
                {
                    return false;
                }
                int revertedNumber = 0;
                while (x > revertedNumber)
                {
                    revertedNumber = revertedNumber * 10 + x % 10;
                    x /= 10;
                }
                return x == revertedNumber || x == revertedNumber / 10;
            }
    }
<think> 我们正在处理关于字符串回文判断的问题。用户希望了解判断字符串是否回文的方法。根据之前的引用,我们可以总结几种常见的方法,并使用Python实现(因为用户之前的问题是关于Python的,但引用中使用了Java、JavaScript和C,这里统一用Python实现)。 回文字符串:正读和反读都相同的字符串(忽略大小写和空格?根据需求,这里我们先不考虑,但可以提及)。 方法总结: 1. 反转字符串法:将原字符串反转后与原字符串比较。 2. 双指针法:使用两个指针分别从字符串的头和尾向中间移动,并比较字符。 3. 递归法:递归比较首尾字符,然后比较去掉首尾的子串(效率较低,但作为方法介绍)。 4. 栈法(半入栈然后比较,但实际中不常用,这里不实现)。 注意:实际应用中,我们可能还需要考虑非字母数字字符的情况(比如只考虑字母和数字,忽略大小写),但这里我们先实现基本方法,然后可以扩展。 我们将实现以下方法: 方法1:反转字符串法 方法2:双指针迭代法 方法3:递归法 然后,我们还可以讨论一下如何处理忽略非字母数字字符和大小写的情况。 代码示例: ```python # 方法1:反转字符串法 def is_palindrome_1(s): # 去除空格并转为小写?这里先不做,根据需求决定 # 如果要求忽略非字母数字和大小写,我们可以先清洗字符串 return s == s[::-1] # 方法2:双指针法 def is_palindrome_2(s): left, right = 0, len(s)-1 while left < right: if s[left] != s[right]: return False left += 1 right -= 1 return True # 方法3:递归法 def is_palindrome_3(s): if len(s) <= 1: return True if s[0] != s[-1]: return False return is_palindrome_3(s[1:-1]) # 测试 test_str = "abcba" print(f"方法1: {test_str} 是回文? {is_palindrome_1(test_str)}") print(f"方法2: {test_str} 是回文? {is_palindrome_2(test_str)}") print(f"方法3: {test_str} 是回文? {is_palindrome_3(test_str)}") test_str2 = "abcde" print(f"方法1: {test_str2} 是回文? {is_palindrome_1(test_str2)}") print(f"方法2: {test_str2} 是回文? {is_palindrome_2(test_str2)}") print(f"方法3: {test_str2} 是回文? {is_palindrome_3(test_str2)}") ``` 但是,如果字符串很长,递归法可能会导致栈溢出,所以不推荐用于长字符串。 扩展:忽略非字母数字字符并忽略大小写 我们可以先对字符串进行清洗,只保留字母数字,并转换为小写(或大写),然后再判断。 例如,LeetCode 125题:验证回文串。 我们可以写一个辅助函数来清洗字符串: ```python import re def clean_string(s): # 移除非字母数字字符,并转换为小写 s = re.sub(r'[^a-zA-Z0-9]', '', s) return s.lower() # 然后我们可以修改上述方法,先清洗字符串判断 def is_palindrome_clean(s): cleaned = clean_string(s) return cleaned == cleaned[::-1] ``` 测试: ```python s = "A man, a plan, a canal: Panama" print(is_palindrome_clean(s)) # 应该返回True ``` 性能比较: - 反转字符串法:需要创建反转后的字符串,空间复杂度$O(n)$(因为字符串不可变,切片会创建新字符串)。 - 双指针法:空间复杂度$O(1)$(如果原地操作,不需要额外空间;但如果先清洗字符串,清洗过程需要额外空间)。 - 递归法:空间复杂度$O(n)$(递归调用栈)。 所以,双指针法在空间上更优,但前提是我们可以在原始字符串上操作(或者清洗后的字符串上使用双指针,但清洗过程需要空间)。 最后,我们还可以考虑用栈(将前半部分入栈,然后与后半部分比较),但这种方法也需要额外空间,且实现并不比双指针简单,所以这里不展开。 总结: - 如果允许使用额外空间,反转字符串法最简单。 - 如果要求空间效率,双指针法更优。 - 递归法不推荐用于长字符串。 相关问题: 1. 如何忽略非字母数字字符并忽略大小写进行回文判断? 2. 如何在不创建新字符串的情况下进行回文判断?(使用双指针,但需要先处理非字母数字字符?实际上无法完全避免,因为需要跳过非字母数字字符,或者我们可以不清理,但在双指针移动时跳过非字母数字字符) 3. 回文判断的时间复杂度是多少? </think> ### Python中字符串回文判断方法 回文字符串是指正读和反读都相同的字符串(如 "level"、"上海自来水来自海上")。以下是5种常用的判断方法及其实现: #### 1. 反转比较法(推荐) ```python def is_palindrome_1(s): cleaned = ''.join(filter(str.isalnum, s)).lower() # 清洗非字母数字字符并转小写 return cleaned == cleaned[::-1] # 测试 print(is_palindrome_1("A man, a plan, a canal: Panama")) # True print(is_palindrome_1("racecar")) # True print(is_palindrome_1("hello")) # False ``` **原理**:清洗字符串后直接比较反转版本[^1][^2] #### 2. 双指针法(空间效率高) ```python def is_palindrome_2(s): cleaned = ''.join(ch.lower() for ch in s if ch.isalnum()) left, right = 0, len(cleaned) - 1 while left < right: if cleaned[left] != cleaned[right]: return False left += 1 right -= 1 return True # 测试 print(is_palindrome_2("Was it a car or a cat I saw?")) # True ``` **优势**:空间复杂度$O(1)$,适合大字符串[^3][^4] #### 3. 递归解法 ```python def is_palindrome_3(s): cleaned = ''.join(filter(str.isalnum, s)).lower() if len(cleaned) <= 1: return True if cleaned[0] != cleaned[-1]: return False return is_palindrome_3(cleaned[1:-1]) # 测试 print(is_palindrome_3("able was I ere I saw elba")) # True ``` **注意**:递归深度限制,不适合超长字符串 #### 4. 使用栈结构 ```python def is_palindrome_4(s): cleaned = ''.join(ch.lower() for ch in s if ch.isalnum()) stack = list(cleaned[:len(cleaned)//2]) start = len(cleaned)//2 if len(cleaned) % 2 != 0: start += 1 # 奇数长度跳过中间字符 for i in range(start, len(cleaned)): if cleaned[i] != stack.pop(): return False return True # 测试 print(is_palindrome_4("12321")) # True ``` #### 5. 使用re正则表达式清洗 ```python import re def is_palindrome_5(s): cleaned = re.sub(r'[^a-z0-9]', '', s.lower()) return cleaned == cleaned[::-1] # 测试 print(is_palindrome_5("No 'x' in Nixon")) # True ``` ### 方法比较 | 方法 | 时间复杂度 | 空间复杂度 | 特点 | |------------|------------|------------|--------------------------| | 反转比较法 | $O(n)$ | $O(n)$ | 最简洁直观 | | 双指针法 | $O(n)$ | $O(1)$ | 空间效率最优 | | 递归法 | $O(n)$ | $O(n)$ | 理解递归思想 | | 栈结构 | $O(n)$ | $O(n)$ | 展示数据结构应用 | | 正则表达式 | $O(n)$ | $O(n)$ | 清洗复杂字符串最便捷 | > **特殊字符处理**:所有方法都通过`.isalnum()`或正则表达式移除非字母数字字符,并通过`.lower()`统一大小写,确保"Racecar"、"A man a plan"这类字符串也能正确判断[^1][^5] ### 性能测试 ```python import timeit test_str = "A man, a plan, a canal: Panama" * 1000 for i in range(1, 6): func = f"is_palindrome_{i}" time = timeit.timeit(f"{func}('{test_str}')", setup=f"from __main__ import {func}", number=100) print(f"方法{i}: {time:.5f}秒/百次") ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值