LeetCode刷题——字符串(python语言)
一、字符串
1.1 字符串定义
字符串就是一系列字符的连接。字符串可以遍历,每次遍历都是字符。
1.2 字符串匹配
首先,我们称待匹配的字符串(长)为主串,用来匹配的字符串(短)为子串(模式串),字符串匹配就是要找到主串中存在模式串的位置。字符串匹配算法主要分为/字符串的朴素匹配)BF算法和(字符串的高效匹配)KMF算法,由于笔者能力有限,这里附上大佬的链接。BF算法和KMF算法的区别
二、刷题
2.1 验证回文串
给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写。
说明:本题中,我们将空字符串定义为有效的回文串。
示例 1:
输入: “A man, a plan, a canal: Panama”
输出: true
解释:“amanaplanacanalpanama” 是回文串
示例 2:
输入: “race a car”
输出: false
解释:“raceacar” 不是回文串
提示:
1 <= s.length <= 2 * 105
字符串 s 由 ASCII 字符组成
#很常规的题,首先排除非字母的和大写的,比较前后是否对称,双指针的思想
class Solution:
def isPalindrome(self, s: str) -> bool:
n = len(s)
i = 0
j = n - 1
while(i<j):
if not (s[i].isalnum()): #排除非字母的
i += 1
continue
if not (s[j].isalnum()): #排除非字母的
j -= 1
continue
if((s[i].lower())==(s[j].lower())): #不区分大小写的
i += 1
j -= 1
else:
return False
return True
# 48 ms 15 MB
2.2 翻转字符串里的单词
给你一个字符串 s ,逐个翻转字符串中的所有 单词 。
单词 是由非空格字符组成的字符串。s 中使用至少一个空格将字符串中的 单词 分隔开。
请你返回一个翻转 s 中单词顺序并用单个空格相连的字符串。
说明:
输入字符串 s 可以在前面、后面或者单词间包含多余的空格。
翻转后单词间应当仅用一个空格分隔。
翻转后的字符串中不应包含额外的空格。
示例 1:
输入:s = “the sky is blue”
输出:“blue is sky the”
示例 2:
输入:s = " hello world "
输出:“world hello”
解释:输入字符串可以在前面或者后面包含多余的空格,但是翻转后的字符不能包括。
示例 3:
输入:s = “a good example”
输出:“example good a”
解释:如果两个单词间有多余的空格,将翻转后单词间的空格减少到只含一个。
示例 4:
输入:s = " Bob Loves Alice "
输出:“Alice Loves Bob”
示例 5:
输入:s = “Alice does not even like bob”
输出:“bob like even not does Alice”
提示:
1 <= s.length <= 104
s 包含英文大小写字母、数字和空格 ’ ’
s 中 至少存在一个 单词
进阶:
请尝试使用 O(1) 额外空间复杂度的原地解法。
#切分(记得去除多余的空格,没找到一次空格,查看是否有单词存储),倒置,连接
#2_1
class Solution:
def reverseWords(self, s: str) -> str:
words = s.split() #按照空格,切分
words.reverse() #倒置
return " ".join(words) #连接
#36 ms 15 MB
#2_2
class Solution:
def reverseWords(self, s: str) -> str:
words = [] #最终的文本库
cur = "" #存储每个字
for ch in s:
if(ch==" "):#如果是空格,判断前方是不是单词
if cur:#是单词,记录了
words.append(cur)#加入文本库
cur = ""#存储转换为空
else:
cur += ch#记录单词的每个字母
if cur:
words.append(cur)#最后一个单词存储
n = len(words)#单词计数
for i in range(n//2):#类似数组,调换每个单词反转
words[i],words[n-1-i] = words[n-1-i],words[i]
#words.reverse() #或者直接反转列表
return " ".join(words)#用空格连接
#40 ms 15.1 MB
2.3 验证回文字符串 Ⅱ
给定一个非空字符串 s,最多删除一个字符。判断是否能成为回文字符串。
示例 1:
输入: s = “aba”
输出: true
示例 2:
输入: s = “abca”
输出: true
解释: 你可以删除c字符。
示例 3:
输入: s = “abc”
输出: false
提示:
1 <= s.length <= 105
s 由小写英文字母组成
#删掉一个字符可以认为时
#3_1
class Solution:
def validPalindrome(self, s: str) -> bool:
n = len(s) #记录字符串长度
i = 0
j = n - 1
delete_s = 1 #删掉一个字符的标记
answer_1 = answer_2 = False #分两次讨论,当不匹配时,删除左字符或者右字符
while(i<=j):
if(s[i]==s[j]):
i += 1
j -= 1
answer_1 = True
elif(delete_s):#删掉左字符
i += 1
delete_s = 0
else:
answer_1 = False
break
i = 0
j = n - 1
delete_s = 1
while(i<=j):
if(s[i]==s[j]):
i += 1
j -= 1
answer_2 = True
elif(delete_s):#删掉右字符
j -= 1
delete_s = 0
else:
answer_2 = False
break
return answer_1 or answer_2
#188 ms 15.2 MB
#3_2
class Solution:
def validPalindrome(self, s: str) -> bool:
if s==s[::-1]:#前后是否相等
return True
l,r=0,len(s)-1#定义左右指针
while l<r:
if s[l]==s[r]:
l+=1
r-=1
else:#不相等时,对不相等部分删除一个左右字符切片
a=s[l+1:r+1]
b=s[l:r]
return a==a[::-1] or b==b[::-1]#判断其中一个是否相同
#52 ms 15.4 MB
#本题陷入蒙圈中,在leetcode上copy的大佬的代码,链接在下面
2.4 Excel表列名称
给你一个整数 columnNumber ,返回它在 Excel 表中相对应的列名称。
例如:
A -> 1
B -> 2
C -> 3
…
Z -> 26
AA -> 27
AB -> 28
…
示例 1:
输入:columnNumber = 1
输出:“A”
示例 2:
输入:columnNumber = 28
输出:“AB”
示例 3:
输入:columnNumber = 701
输出:“ZY”
示例 4:
输入:columnNumber = 2147483647
输出:“FXSHRXW”
提示:
1 <= columnNumber <= 231 - 1
#4_1
class Solution:
def convertToTitle(self, columnNumber: int) -> str:
res = ""
#因为有26个字母,但是0和26对26取余都是0,所以向商借一位,排除0的因素
while(columnNumber>0):
columnNumber, y = divmod(columnNumber, 26) #对数组对26取余
if y == 0: #如果余数是0,因为排除为0的因素,我们从1-26编号。
columnNumber -= 1#从商借一位
y = 26#余数为26
res = chr(y + 64) + res#字符串加法构造,chr对应将ASCII2码转化为字符,ord相反,ord(A)是65
return res
#52 ms 15.4 MB
#4_2 和正常 0~25 的 26 进制相比,本质上就是每一位多加了 1。假设 A == 0,B == 1,那么 AB = 26 * 0 + 1 * 1,而现在 AB = 26 * (0 + 1) + 1 * (1 + 1),所以只要在处理每一位的时候减 1,就可以按照正常的 26 进制来处理
class Solution:
def convertToTitle(self, columnNumber: int) -> str:
res = ""
while(columnNumber>0):
columnNumber -= 1
columnNumber, y = divmod(columnNumber, 26)
res = chr(y + 65) + res
return res
#24 ms 14.8 MB
#4_3 思路同2
class Solution:
def convertToTitle(self, n: int) -> str:
return "" if n == 0 else self.convertToTitle((n - 1) // 26) + chr((n - 1) % 26 + 65)
#36 ms 15 MB
作者:powcai
链接:https://leetcode-cn.com/problems/excel-sheet-column-title/solution/shi-jin-zhi-zhuan-26jin-zhi-by-powcai/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
2.5 字符串解码
给定一个经过编码的字符串,返回它解码后的字符串。
编码规则为: k[encoded_string],表示其中方括号内部的 encoded_string 正好重复 k 次。注意 k 保证为正整数。
你可以认为输入字符串总是有效的;输入字符串中没有额外的空格,且输入的方括号总是符合格式要求的。
此外,你可以认为原始数据不包含数字,所有的数字只表示重复的次数 k ,例如不会出现像 3a 或 2[4] 的输入。
示例 1:
输入:s = “3[a]2[bc]”
输出:“aaabcbc”
示例 2:
输入:s = “3[a2[c]]”
输出:“accaccacc”
示例 3:
输入:s = “2[abc]3[cd]ef”
输出:“abcabccdcdcdef”
示例 4:
输入:s = “abc3[cd]xyz”
输出:“abccdcdcdxyz”
提示:
1 <= s.length <= 30
s 由小写英文字母、数字和方括号 ‘[]’ 组成
s 保证是一个 有效 的输入。
s 中所有整数的取值范围为 [1, 300]
#5 正则化写法
class Solution:
def decodeString(self, s: str) -> str:
def encode(t: str) -> str:
i = t.find('[')
return int(t[:i]) * t[i+1:-1]
regex = re.compile(r'\d+\[\w*\]')
mo = regex.search(s)
while mo:
s = s.replace(mo.group(), encode(mo.group()))
mo = regex.search(s)
return s
#28 ms 15.1 MB
#5_2 用栈写
class Solution:
def decodeString(self, s: str) -> str:
# nums保存倍数
nums = []
stack = []
# temp 保存[与]之间的字符串
temp = []
num = ''
for i in s:
# 当遇到数字字符时,将其合并起来,后面转换为倍数,比如:'66'
if i.isdigit():
num += i
continue
# 通过判断,将num中的数字字符串转换为,int并保存进nums中,只有当num的长度大于0,且i不为数字的时候,才将数字存进去
if not i.isdigit() and len(num)>0:
nums.append(int(num))
num = ''
# 当遇到右括号],开始出栈,直到遇到[停止
if i == ']':
# 将stack中的字符出栈,直到遇到[停止
m = stack.pop()
while m != '[':
temp.append(m)
m = stack.pop()
# [的左边一定为数字,即[...,s_num,'['],所以stack.pop()即为倍数
s_num = nums.pop()
# 部分翻倍的字符串
# 字符出栈的方向与原字符方向相反,所以注意反向回来
s_str = ''.join(temp[::-1])
# 将翻倍的字符串推进stack中
# s_num是倍数
while s_num:
for j in s_str:
stack.append(j)
s_num -= 1
temp = []
else:
stack.append(i)
return ''.join(stack)
#36 ms 15.2 MB