字符串算法总结
替换空格(没什么好说的,白给题)
class Solution:
# s 源字符串
def replaceSpace(self, s):
# write code here
l = len(s.split(' '))
a = ''
for i in range(l-1):
a += s.split(' ')[i] + '%20'
a = a+s.split(' ')[l-1]
return a
字符串的全排列
class Solution:
def Permutation(self, ss):
if len(ss) <= 1:
return ss
res = set()
# 遍历字符串,固定第一个元素,第一个元素可以取a,b,c...,然后递归求解
for i in range(len(ss)):
for j in self.Permutation(ss[:i] + ss[i+1:]): # 依次固定了元素,其他的全排列(递归求解)
res.add(ss[i] + j) # 集合添加元素的方法add(),集合添加去重(若存在重复字符,排列后会存在相同,如baa,baa)
return sorted(res) # sorted()能对可迭代对象进行排序,结果返回一个新的list
#DFS全排列加去重
class Solution:
def permuteUnique(self, nums: List[int]) -> List[List[int]]:
self.result = []
size = len(nums)
def dfs(res):
if len(res)==size:
self.result.append(res[:])
return
for i in range(len(nums)):
#去掉相邻重复元素数组
if i>0 and nums[i]==nums[i-1] and not list1[i-1]:
continue
if list1[i]:
continue
#是否选用,建立标志位
list1[i] = True
res.append(nums[i])
dfs(res)
list1[i] = False
res.pop()
list1 = [False for _ in range(len(nums))]
nums.sort()
dfs([])
return self.result
第一次只出现一次的字符(哈希)
class Solution:
def FirstNotRepeatingChar(self, s):
# write code here
ls=[0]*256
#遍历字符串,下标为ASCII值,值为次数
for i in s:
ls[ord(i)]+=1
#遍历列表,找到出现次数为1的字符并输出位置
for j in s:
if ls[ord(j)]==1:
return s.index(j)
return -1
左旋字符串(两次翻转)
# -*- coding:utf-8 -*-
class Solution:
def reverse(self, s):
if not s:
return ""
length = len(s)
if length <= 0:
return ""
s = list(s)
#print s
start = 0
end = length - 1
while start < end:
s[start], s[end] = s[end], s[start]
start += 1
end -= 1
#print 'after', s
return ''.join(s)
def LeftRotateString(self, s, n):
# write code here
if not s:
return ""
length = len(s)
if length <= 0:
return ""
if n > length:
n = n % length
s = self.reverse(s)
first = ""
second = ""
for i in range(length - n):
first += s[i]
first = self.reverse(first)
for i in range(length - n, length, 1):
second += s[i]
second = self.reverse(second)
return first + second
判断字符串是否为合法数字
class Solution:
def StrToInt(self, s):
# write code here
# 先排除异常特殊情况
if s in ['','-','+','+-','-+']:
return 0
count = 0
# 只要有非法字符就不过
for i in s:
# 检查字母
if i not in '0123456789+-':
count += 1
# 只要-+号不在第一位就不过
for i in s[1:]:
if i not in '0123456789':
count += 1
if count:
return 0
return int(s)
最小覆盖子串
from collections import defaultdict
class Solution:
def minWindow(self, s: str, t: str) -> str:
count_s = defaultdict(int)
count_t = defaultdict(int)
for x in t:
count_t[x] +=1
left = 0
valid = 0
start = -1
minlen = float(inf)
for right in range(len(s)):
x = s[right]
if x in count_t:
count_s[x] +=1
if count_s[x] == count_t[x]:
valid +=1
while valid == len(count_t):
if right - left<minlen:
minlen = right-left
start = left
l = s[left]
left +=1
if l in count_s:
count_s[l] -=1
if count_s[l] < count_t[l]:
valid -=1
if start == -1:
return ''
return s[start:start+minlen+1]
表示数值的字符串
class Solution:
# s字符串
def isNumeric(self, s):
# write code here
if len(s) <= 0:
return False
# 分别标记是否出现过正负号、小数点、e,因为这几个需要特殊考虑
has_sign = False
has_point = False
has_e = False
for i in range(len(s)):
# 对于e的情况
if s[i] == 'E' or s[i] == 'e':
# 不同出现两个e
if has_e:
return False
# e不能出现在最后面,因为e后面要接数字
else:
has_e = True
if i == len(s) -1:
return False
# 对于符号位的情况
elif s[i] == '+' or s[i] == '-':
# 如果前面已经出现过了符号位,那么这个符号位,必须是跟在e后面的
if has_sign:
if s[i-1] != 'e' and s[i-1] != 'E':
return False
# 如果这是第一次出现符号位,而且出现的位置不是字符串第一个位置,那么就只能出现在e后面
else:
has_sign = True
if i > 0 and s[i-1] != 'e' and s[i-1] != 'E':
return False
# 对于小数点的情况
elif s[i] == '.':
# 小数点不能出现两次;而且如果已经出现过e了,那么就不能再出现小数点,因为e后面只能是整数
if has_point or has_e:
return False
# 如果是第一次出现小数点,如果前面出现过e,那么还是不能出现小数点
else:
has_point = True
if i > 0 and (s[i-1] == 'e' or s[i-1] == 'E'):
return False
else:
# 其他字符必须是‘0’到‘9’之间的
if s[i] < '0' or s[i] > '9':
return False
return True
单词接龙
from typing import List
from collections import deque
class Solution:
def ladderLength(self, beginWord: str, endWord: str, wordList: List[str]) -> int:
word_set = set(wordList)
if len(word_set) == 0 or endWord not in word_set:
return 0
if beginWord in word_set:
word_set.remove(beginWord)
#储存队列
queue = deque()
queue.append(beginWord)
#防止重复
visited = set(beginWord)
visited.add(beginWord)
step = 1
while queue:
current_size = len(queue)
#queue中可能有多个与上一次迭代的单词相差一个编辑距离的单词
for i in range(current_size):
word = queue.popleft()
word_list = list(word)
for j in range(len(word_list)):
origin_char = word_list[j]
#扩散寻找
for k in range(26):
word_list[j] = chr(ord('a') + k)
next_word = ''.join(word_list)
if next_word in word_set:
#判断是否到达终点
if next_word == endWord:
return step + 1
if next_word not in visited:
queue.append(next_word)
word_set.remove(next_word)
#跟回溯一样返回原状态
word_list[j] = origin_char
step += 1
return 0
移掉K位数字
给定一个以字符串表示的非负整数num,移除这个数中的K位数字,使得最后剩下的数字最小。
class Solution:
def removeKdigits(self, num: str, k: int) -> str:
if not num or len(num)<=k:
return '0'
count = 0
res = ''
begin = 0
max_len = len(num)-k
#类似于滑动窗口的思想,最后剩下length-k个数字
while count < max_len:
min_index = 0
min_num = float('inf')
#每K个长度的窗口选一个最小的数字
for i in range(begin,k+count+1):
if int(num[i])<min_num:
min_index = i
min_num = int(num[i])
res +=str(min_num)
begin = min_index+1
count +=1
return str(int(res))
字符串的排列
字符串的全排列
import collections
class Solution(object):
def checkInclusion(self, s1, s2):
"""
:type s1: str
:type s2: str
:rtype: bool
"""
l1, l2 = len(s1), len(s2)
c1 = collections.Counter(s1)
c2 = collections.Counter()
cnt = 0 #统计变量,全部26个字符,频率相同的个数,当cnt==s1字母的个数的时候,就是全部符合题意,返回真
p = q = 0 #滑动窗口[p,q]
while q < l2:
c2[s2[q]] += 1
if c1[s2[q]] == c2[s2[q]]: #对于遍历到的字母,如果出现次数相同
cnt += 1 #统计变量+1
if cnt == len(c1): #判断结果写在前面,此时证明s2滑动窗口和s1全部字符相同,返回真
return True
q += 1 #滑动窗口右移
if q - p + 1 > l1: #这是构造第一个滑动窗口的特殊判断,里面内容是维护边界滑动窗口
if c1[s2[p]] == c2[s2[p]]: #判断性的if写在前面,因为一旦频率变化,这个统计变量就减1
cnt -= 1
c2[s2[p]] -= 1 #字典哈希表移除最前面的字符
if c2[s2[p]] == 0: #由于counter特性,如果value为0,必须删除它
del c2[s2[p]]
p += 1 #最前面的下标右移动
return False
KMP字符串的排列
'''
字符串匹配
'''
def KMP(pat):
x = 0
for i in range(m):
for c in range(256):
if c == ord(pat[i]):
dp[i][c] = i+1
else:
dp[i][c] = dp[x][c]
x = dp[x][ord(pat[i])]
def search(txt):
n = len(txt)
j = 0
for i in range(n):
j = dp[j][ord(txt[i])]
if (j==m):
return (i-m+1)
return -1
if __name__ == "__main__":
pat = 'aaab'
txt = 'aaacaaab'
m = len(pat)
dp = [[0]*256 for _ in range(m)]
dp[0][0] = 1
KMP(pat)
print(search(txt))
无重复字符的最长子串
'''
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
'''
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
if not s:
return 0
left = 0
right = 0
n = len(s)
max_list = []
res = 0
for i in range(n):
if s[i] not in max_list:
max_list.append(s[i])
right += 1
else:
max_list.append(s[i])
while max_list[0] != s[i]:
max_list.pop(0)
left += 1
max_list.pop(0)
left += 1
res = max(res,len(max_list))
return res
a = Solution()
s = "abcabcbb"
print(a.lengthOfLongestSubstring(s))
字符串转换整数
'''
请你来实现一个 atoi 函数,使其能将字符串转换成整数。
首先,该函数会根据需要丢弃无用的开头空格字符,直到寻找到第一个非空格的字符为止。接下来的转化规则如下:
如果第一个非空字符为正或者负号时,则将该符号与之后面尽可能多的连续数字字符组合起来,形成一个有符号整数。
假如第一个非空字符是数字,则直接将其与之后连续的数字字符组合起来,形成一个整数。
该字符串在有效的整数部分之后也可能会存在多余的字符,那么这些字符可以被忽略,它们对函数不应该造成影响。
'''
import re
class Solution:
def myAtoi(self, str: str) -> int:
INT_MAX = 2147483647
INT_MIN = -2147483648
str = str.lstrip() #清除左边多余的空格
#正则匹配 ^代表匹配开头 [\+\-\s] 代表匹配+-空白 ?代表匹配一个或0个 \d+代表匹配多个数字
num_re = re.compile(r'^[\+\-\s]?\d+') #设置正则规则
num = num_re.findall(str) #查找匹配的内容
num = int(*num) #由于返回的是个列表,解包并且转换成整数
return max(min(num,INT_MAX),INT_MIN) #返回值