验证回文串 总结

提一个非常简单的问题:如何验证回文串。
最先想到的是,把字符串反转,然后和原字符串比较。
那么顺势总结一下字符串反转的方法。
有的小伙伴可能会想到reverse()方法。但要注意,reverse()是列表才有的方法,用于字符串会报错。当然,把字符串转换成列表就可以:
ls = list(mystr)
ls.reverse()
mystr1 = ''.join(ls)
不过,这又是何必呢。


内置函数reversed()可以用于各种序列,包括元组、列表、字符串、range等。要注意的是,它返回的是迭代器。
mystr1 = ''.join(list(reversed(mystr)))
这未免还是不太方便。


别忘了,python有切片大法!
mystr1 = mystr[::-1]
简洁!优美!得劲!
于是验证回文串的函数完成了:

# 判断回文串
def isp(s):
    return s == s[::-1]

这个方法好是好,但它仍然不可避免地需要完成一次字符串反转。我的理解是,它不得不进行一次对字符串的完整遍历。
于是,以“双指针”为噱头的解法出现了。
说得这么玄乎,其实道理很简单:

  1. 左右两个指针分别指向字符串两端的字符;
  2. 不断地将两个指针相向移动,每次移动一步,并判断它们指向的字符是否相同,如果相同就继续移动一步,如果不同就说明不是回文串;
  3. 当两个指针相遇时,就说明是回文串。

这个思路,大致有两种写法:

# 判断回文串
def isp1(s):
    length = len(s)
    for i in range(length//2):
        if s[i]!=s[length-i-1]:
            return False
    return True
# 判断回文串
def isp2(s):
    left, right = 0,len(s)-1
    while left < right:
        if s[left] != s[right]:
            return False
        left, right = left + 1, right - 1
    return True

我原以为不涉及字符串反转的双指针法会快一些,然而事实是,经测试,上述两种代码的运行速度都显著低于字符串反转。
所以说,还是切片厉害啊。


回到leetcode原题目:给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,忽略字母的大小写。
最开始,我立刻把题目拆解成两部分:处理字符串和验证回文串。而官方标答给出了一种骚操作:不事先处理字符串,直接在原始字符串上进行比较。
如果不对字符串做提前处理,压力就转移到遍历时的每个字符身上,要先判断该字符是否为字母或数字,然后统一字母大小写。
思路本身是简单的,要读懂代码需要稍微转一下脑子,注意看注释:

# 判断回文串,官方标答
def isPalindrome(s):
    left, right = 0, len(s) - 1

    while left < right:
        # 左指针不断地向右移动,直到遇到一个字母或数字字符,或者两指针重合
        while left < right and not s[left].isalnum():
            left += 1
        # 右指针不断地向左移动,直到遇到一个字母或数字字符,或者两指针重合
        while left < right and not s[right].isalnum():
            right -= 1
        if left < right:
            if s[left].lower() != s[right].lower():
                return False
            left, right = left + 1, right - 1

    return True

经测试,这个方法在时间上没有任何优势,但占用的内存空间减小了,说明它具有较小的空间复杂度。
不过,像我这种菜鸟,能考虑好时间复杂度就不错了!

参考资料:
https://leetcode-cn.com/problems/valid-palindrome/solution/yan-zheng-hui-wen-chuan-by-leetcode-solution/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值