python 字符串(基础四)

题目:力扣

1. 验证是否为回文串

给定一个字符串 ,包含空字符串, 数字,英文字符,以及各种符号

s =  "A man, a plan, a canal: Panama"

要求:忽略符号,只保留英文字符串和数字, 使得保留下的字符串正序,到序均为同一个字符串;

将空字符串定义为有效的回文串; 如果是回文串返回True, 否返回False

"""
python 切片:
 [-1] [:-1] [::-1] [n::-1]都是python中切片的使用方法;
 [-1]:获取最后一个元素,类似于matlab中的end;
 [:-1]:除了最后一个元素,获取其他所有的元素;
 [::-1]:对第一个到最后一个元素进行倒序之后取出;
 [n::-1]:对第一个到第n个元素进行倒序后取出。
"""

"""
正则表达式[\w]+,\w+,[\w+] 三者有何区别:
[\w]+和\w+没有区别,都是匹配数字和字母下划线的多个字符;
[\w+]表示匹配数字、字母、下划线和加号本身字符;
[\w_+]表示匹配数字、字母、下划线和加号本身字符;
"""

def isPalindrome(s):
    s_sub = str.lower(re.sub('[\W_+]','',s))
    s_rev = s_sub[::-1]
    if s_sub == s_rev:
        return True
    else:
        return False

def isPalindrome(s):
    # isalpha()检测是否只有数字, isdigit()检测是否只有数字
    s = s.lower()
    c = "".join([x for x in s if x.isalpha() or x.isdigit()])
    k = "".join([c[i] for i in range(len(c)-1, -1, -1)])
    return c==k

思路:

1. 利用正则表达式 获取字符串中的数字和英文字符

2. 将字符串转换成小写, 然后利用python 的切片倒序   

3. 最后判断比较    

2. 字符串转换为整数

实现一个 myAtoi(string s) 函数,使其能将字符串转换成一个 32 位有符号整数

函数 myAtoi(string s) 的算法如下:

1. 读入字符串并丢弃无用的前导空格
2. 检查下一个字符(假设还未到字符末尾)为正还是负号,读取该字符(如果有)。 确定最终结      果是负数还是正数。 如果两者都不存在,则假定结果为正。
3. 读入下一个字符,直到到达下一个非数字字符或到达输入的结尾。字符串的其余部分将被忽略。
    将前面步骤读入的这些数字转换为整数(即,"123" -> 123, "0032" -> 32)。如果没有读入数      字,则整数为 0 。必要时更改符号(从步骤 2 开始)。
4. 如果整数数超过 32 位有符号整数范围 [−2**31,  2**31 − 1] ,需要截断这个整数,使其保持在        这   个范围内。具体来说,小于 −2**31 的整数应该被固定为 −2**31 ,大于 2**31 − 1 的整数应      该被固定为 2**31 − 1 。
5. 返回整数作为最终结果。

注意:本题中的空白字符只包括空格字符 ' ' ;  除前导空格或数字后的其余字符串外,请勿忽略任何其他字符。

正则解法:

"""
^:匹配字符串开头
[\+\-]:代表一个+字符或-字符
?:前面一个字符可有可无
\d:一个数字
+:前面一个字符的一个或多个
\D:一个非数字字符
*:前面一个字符的0个或多个
"""
# 字符串转换为整数

def myAtoi(s):
    it_c = max(min(int(*re.findall('^[\+\-]?\d+', s.lstrip())), 2**31 - 1), -2**31)
    return int(it_c)

def myAtoi(s):
    INT_MAX = 2147483647    
    INT_MIN = -2147483648
    ss = s.lstrip() #清除左边多余的空格
    num_re = re.compile(r'^[\+\-]?\d+')   #设置正则规则
    num = num_re.findall(ss)   #查找匹配的内容
    num = int(*num) #由于返回的是个列表,解包并且转换成整数
    print("num", num)
    return max(min(num,INT_MAX),INT_MIN)    #返回值

力扣 官方解法 自动机思路:

假设程序在每个时刻有一个状态 s,每次从序列中输入一个字符 c,并根据字符 c 转移到下一个状态 s'。这样,我们只需要建立一个覆盖所有情况的从 s 与 c 映射到 s' 的表格即可解决题目中的问题。

fig1

 '+/-numberother
startstartsignedin_numberend
signedendendin_numberend
in_numberendendin_numberend
endendendendend

另外自动机也需要记录当前已经输入的数字,只要在 s' 为 in_number 时,更新我们输入的数字,即可最终得到输入的数字。

INT_MAX = 2 ** 31 - 1
INT_MIN = -2 ** 31

class Automaton:
    def __init__(self):
        self.state = 'start'
        self.sign = 1
        self.ans = 0
        self.table = {
            'start': ['start', 'signed', 'in_number', 'end'],
            'signed': ['end', 'end', 'in_number', 'end'],
            'in_number': ['end', 'end', 'in_number', 'end'],
            'end': ['end', 'end', 'end', 'end'],
        }
        
    def get_col(self, c):
        if c.isspace():
            return 0
        if c == '+' or c == '-':
            return 1
        if c.isdigit():
            return 2
        return 3

    def get(self, c):
        self.state = self.table[self.state][self.get_col(c)]
        if self.state == 'in_number':
            self.ans = self.ans * 10 + int(c)
            self.ans = min(self.ans, INT_MAX) if self.sign == 1 else min(self.ans, -INT_MIN)
        elif self.state == 'signed':
            self.sign = 1 if c == '+' else -1

class Solution:
    def myAtoi(self, str: str) -> int:
        automaton = Automaton()
        for c in str:
            automaton.get(c)
        return automaton.sign * automaton.ans

复杂度分析:

时间复杂度:O(n),其中 n 为字符串的长度。我们只需要依次处理所有的字符,处理每个字符需要的时间为 O(1);

空间复杂度:O(1)。自动机的状态只需要常数空间存储

3. 子字符串

给定两个字符串 haystack 和 needle ,在 haystack 字符串中找出 needle 字符串出现的第一个位置(下标从 0 开始);  如果不存在,则返回  -1; 当 needle 是空字符串时,应当返回 0 

def strStr(haystack, needle):
    if needle in haystack and needle != "":
        return haystack.index(needle)
    elif needle == "":
        return 0
    else:
        return -1

4. 外观数列

给定一个正整数 n ,输出外观数列的第 n 项;「外观数列」是一个整数序列,从数字 1 开始,序列中的每一项都是对前一项的描述。

递归公式定义的数字字符串序列:

countAndSay(1) = "1",countAndSay(n) 是对 countAndSay(n-1) 的描述,然后转换成另一个数字字符串

例:

1.     1
2.     11
3.     21
4.     1211
5.     111221
第一项是数字 1 
描述前一项,这个数是 1 即 “ 一 个 1 ”,记作 "11"
描述前一项,这个数是 11 即 “ 二 个 1 ” ,记作 "21"
描述前一项,这个数是 21 即 “ 一 个 2 + 一 个 1 ” ,记作 "1211"
描述前一项,这个数是 1211 即 “ 一 个 1 + 一 个 2 + 二 个 1 ” ,记作 "111221"

"""
1. 当递归出口 n=1时 为1
2. 对上一个(n-1)结果进行遍历获取值
3. 设定计数器,计算同一个数字出现的次数
4. 如果数字相同,计数器加一
5. 若当前不满足,则将上次的值记录下,并重置计数器,重置需要判断是否重复的字符
6. 将最后的结果也追加到字符串上
"""

def is_c(n):
    start, end = 0, 0
    if n== 1:
        return '1'
    s = is_c(n-1)
    ans = '' # 计数器
    start, end = 0, 0
    while end < len(s):
        while end < len(s) and s[start] == s[end]: # 3
            end += 1 # 4
        ans += str(end - start) + s[start] # 5
        start = end
    return ans

5. 最长公共前缀

查找字符串数组中的最长公共前缀,若不存在公共前缀,返回空字符串 ""

输入:strs = ["flower","flow","flight"]
输出:"fl"
"""
先取第一个字符串当做他们的公共前缀
然后找出他和第2个字符串的公共前缀,然后再用这个找出的公共前缀分别和第3个,第4个……取最长的公共前缀

"""
def commonPrefix(strs):
    if len(strs)==0:
        return ''
    pre = strs[0] # 第一个字符串
    strs = strs[1:] # 第一个之后的字符串
    for i in range(len(strs)): 
        count = 0
        # 比较第一个字符串和 之后字符串的长度, 取长度最小的length
        if len(pre) < len(strs[i]): 
            length = len(pre)
        else:
            length = len(strs[i])
        
        for j in range(length):
            if strs[i][j] == pre[j]: # 比较字符串对于位置是否相等
                count += 1
            else:
                break
        # 截取
        pre = pre[:count]
    return pre

"""
zip()是python 的内建函数,zip()函数接受一系列可迭代对象作为参数,
将不同对象中相对应的元素打包成一个元组(tuple),返回由这些元组组成的list列表,
如果传入的参数的长度不等,则返回的list列表的长度和传入参数中最短对象的长度相同
例1:
a =[1, 4, 5, 7]
b =[9, 5, 6, 8]
result = list(zip(a, b, c))
result: [(1, 9, 3), (4, 5, 5), (5, 6, 2), (7, 8, 7)]

例2:
res = ['flower', 'flow', 'filter']
for i in zip(*res):
    print(i, set(i))
('f', 'f', 'f') {'f'}
('l', 'l', 'i') {'l', 'i'}
('o', 'o', 'l') {'l', 'o'}
('w', 'w', 't') {'w', 't'} 
"""

def commonPrefix(strs):
    result = ''
    for i in zip(*strs):
        if len(set(temp)) ==1:
            result += temp[0]
        else:
            break
    return result

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值