数据结构与算法——其他关于字符串的题目

一、字符串转换整数 (atoi)

此题为leetcode第8题
思路:当然如果用正则表达式的话可能只需寥寥一行,但此题并不是想考察python的正则表达式。此题的常规做法就是按照规则一点一点来,并没有什么特殊的知识点。不过还有一种叫自动机的解法,我认为比较有意思,它抽象出start、end、signed、number这几个状态来,遍历字符串,根据规则来进行状态转移。这样的自动机如下图所示:
在这里插入图片描述
也可以用下面的表格表示:
在这里插入图片描述

# 常规解法
class Solution:
    def myAtoi(self, str: str) -> int:
        # 规则
        for i in range(len(str)):
            if str[i] == ' ':
                i += 1
            else:
                str = str[i:]
                break
        res = []
        a = 0
        positive = True
        for k, s in enumerate(str):
            if k == 0 and s == '+':
                positive = True
            elif k == 0 and s == '-':
                positive = False
            elif not (ord(s)-48 >= 0 and ord(s)-48<=9):
                break
            else:
                num_flag = True
                res.append(ord(s)-48)
        if res:
            res = res[::-1]
            for i in range(len(res)):
                a += 10**i * res[i]
            if not positive:
                a = -a
            if a < 0:
                return max(a, -2**31)
            elif a >= 0:
                return min(a, 2**31-1)
        else:
            return 0
class Automation:
    def __init__(self):
        self.state = 'start'
        self.sign = 1
        self.res = 0
        self.states = {
            'start': ['start', 'signed', 'num', 'end'],
            'signed': ['end', 'end', 'num', 'end'],
            'num': ['end', 'end', 'num', 'end'],
            'end': ['end', 'end', 'end', 'end']
        }
    
    def get_state(self, c):
        if c.isspace():
            return self.states[self.state][0]
        elif c == '+' or c == '-':
            return self.states[self.state][1]
        elif c.isdigit():
            return self.states[self.state][2]
        else:
            return self.states[self.state][3]
    
    def get(self, c):
        self.state = self.get_state(c)
        if self.state == 'num':
            self.res = self.res * 10 + int(c)
            self.res = min(INT_MAX, self.res) if self.sign == 1 else min(-INT_MIN, self.res)
        if self.state == 'signed':
            self.sign = 1 if c == '+' else -1

class Solution:
    def myAtoi(self, str: str) -> int:
        # 自动机
        auto = Automation()
        for s in str:
            auto.get(s)
        return auto.sign * auto.res

二、最长公共前缀

此题为leetcode第14题
思路:从左往右纵向比较即可

class Solution:
    def longestCommonPrefix(self, strs: List[str]) -> str:
        # 纵向比较
        if len(strs) == 0:
            return ''
        if len(strs) == 1:
            return strs[0]
        
        res = []
        for i in range(len(strs[0])):
            for j in range(len(strs)):
                if len(strs[j]) <= i or strs[j][i] != strs[0][i]:
                    return ''.join(res)
            res.append(strs[0][i])
        return ''.join(res)

三、二进制求和

此题为leetcode第67题
思路:由于a、b字符串长度不一定相等,因此可以右对齐然后前面填0使两者对其,使用字符串的zfill()方法。然后从后面依次遍历,设置一个初始为0的carry标志位,如果字符为’1’,那么carry+1。如果carry为2或0,那么当前位变为0;如果carry为1或3,那么当前位边为1。当然还有进位需要考虑,carry为2或3时需要进1位,carry为0或1时不需要进位,那么carry变为carry // 2即可。

class Solution:
    def addBinary(self, a: str, b: str) -> str:
        n = max(len(a), len(b))
        a, b = a.zfill(n), b.zfill(n)
        
        res = ''
        carry = 0
        for i in range(n - 1, -1, -1):
            if a[i] == '1':
                carry += 1
            if b[i] == '1':
                carry += 1
            
            if carry % 2 == 0:
                res = '0' + res
            elif carry % 2 == 1:
                res = '1' + res
            carry //= 2
            
        if carry == 1:
            res = '1' + res
        return res

四、反转字符串

此题为leetcode第344题
思路:迭代解法:前后两个指针,不重合时依次字符互换;递归解法:前后两个指针所指的字符互换后,其所夹的子串为子问题,传入helper函数中递归。

class Solution:
    def reverseString(self, s: List[str]) -> None:
        """
        Do not return anything, modify s in-place instead.
        """
        # 迭代
        left, right = 0, len(s) - 1
        while left < right:
            s[left], s[right] = s[right], s[left]
            left += 1
            right -= 1
class Solution:
    def reverseString(self, s: List[str]) -> None:
        """
        Do not return anything, modify s in-place instead.
        """
        # 递归
        def helper(left, right):
            if left < right:
                s[left], s[right] = s[right], s[left]
                helper(left+1, right-1)
        
        helper(0, len(s)-1)

五、验证回文串

此题为leetcode第125题
思路:首先可以都转为小写字母。然后首尾两个指针,依次对比,如果两边都为数字或字母且相等,那么指针就都移动一位;如果都为数字或字母但不相等,那么直接退出返回False;如果有哪个指针为非字母或数字,那么这一轮他就移动一步,忽略这个字母。当然可以用比较pythonic的写法,两行搞定

# 解法1
class Solution:
    def isPalindrome(self, s: str) -> bool:
        s = s.lower()
        left, right = 0, len(s) - 1
        
        def check(ss):
            if 'a' <= ss <= 'z' or '0' <= ss <= '9':
                return True
            else:
                return False
            
        while left < right:
            if check(s[left]) and check(s[right]):
                if s[left] != s[right]:
                    return False
                left += 1
                right -= 1
            elif check(s[left]) and not check(s[right]):
                right -= 1
            elif not check(s[left]) and check(s[right]):
                left += 1
            else:
                left += 1
                right -= 1
        return True
# 解法2
class Solution:
    def isPalindrome(self, s: str) -> bool:
        s = ''.join(filter(str.isalnum, s.lower()))
        return s == s[::-1]

六、验证回文字符串II

此题为leetcode第680题
思路:和上一题比较类似,也是首尾双指针,如果字符相等的话就各自移动一位;如果不相等话,就忽略左边一位或忽略右边一位,继续比较,如果又遇上不相等的,那就不是回文字符串。

class Solution:
    def validPalindrome(self, s: str) -> bool:
        def check(l, r,):
            while l < r:
                if s[l] == s[r]:
                    l += 1
                    r -= 1
                else:
                    return False
            return True
        
        left, right = 0, len(s) - 1
        while left < right:
            if s[left] == s[right]:
                left += 1
                right -= 1
            else:
                return check(left + 1, right) or check(left, right - 1)
        
        return True
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值