目录
1. 判断是否为回文字符串(双指针)
class Solution:
def judge(self , str: str) -> bool:
left = 0
right = len(str)-1
while left < right:
if str[left] != str[right]:
return False
left += 1
right -= 1
return True
2. 反转字符串
class Solution:
def solve(self , str: str) -> str:
res = ""
for i in range(len(str)-1, -1, -1):
res += str[i]
return res
# Python特性方法:return str[::-1]
3. 字符串变形(字母大小写切换)
class Solution:
def trans(self , s: str, n: int) -> str:
if n == 0: return s
res = ""
for i in range(n):
if s[i] >= 'A' and s[i] <= 'Z':
res += chr(ord(s[i]) - ord('A') + ord('a'))
elif s[i] >= 'a' and s[i] <= 'z':
res += chr(ord(s[i]) - ord('a') + ord('A'))
else:
res += s[i]
res = list(res.split(' '))[::-1]
return ' '.join(res)
4. 最长回文子串
暴力法:
class Solution:
# 验证是否是回文
def Valid(self, s: str, l: int, r: int) -> bool:
while l < r:
if s[l] != s[r]:
return False
l += 1
r -= 1
return True
def getLongestPalindrome(self , A: str) -> int:
# 记录最长回文子串的长度
maxlen = 1
# 记录最长回文子串的起始点
begin = 0
for i in range(len(A)-1):
for j in range(len(A)-1, i, -1):
if j-i+1 > maxlen and self.Valid(A, i, j):
maxlen = j-i+1
begin = i
break
# 最长回文子串为:A[begin:begin+maxlen]
return maxlen
中心扩散法:
class Solution:
# 中心扩散
def fun(self, s: str, begin: int, end: int) -> int:
# 每个中心点开始扩散
while begin >= 0 and end <= len(s)-1 and s[begin] == s[end]:
begin -= 1
end += 1
# 返回长度
return end - begin - 1
def getLongestPalindrome(self , A: str) -> int:
maxlen = 1
# 以每个点为中心
for i in range(len(A) - 1):
# 分奇数长度 和 偶数长度向两边扩展
maxlen = max(maxlen, max(self.fun(A, i, i), self.fun(A, i, i+1)))
return maxlen
———————— E N D ———————— E N D ———————— E N D ————————
# 若获取最长子串的方法
def getLongestPalindrome(self , A: str) -> int:
maxlen = 1
begin = 0
# 以每个点为中心
for i in range(len(A) - 1):
max_now = max(self.fun(A, i, i), self.fun(A, i, i+1))
if maxlen < max_now:
maxlen = max_now
begin = i - (maxlen-1)//2
return A[begin:begin+maxlen]
5. 无重复字符的最长子串
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
if len(s) <= 1: return len(s)
ss = set()
start = 0
res = 0
for i in range(len(s)):
while s[i] in ss:
ss.remove(s[start])
start += 1
ss.add(s[i])
res = max(res, i - start + 1)
return res
6. 最长公共子串
class Solution:
def LCS(self , str1: str, str2: str) -> str:
# 让str1为较长的字符串
if len(str1) < len(str2):
str1 ,str2 = str2, str1
res = ""
length = 0
for i in range(len(str1)):
if str1[i-length : i+1] in str2:
res = str1[i-length: i+1]
length += 1
return res
7. 最长公共前缀
class Solution:
def longestCommonPrefix(self , strs: List[str]) -> str:
n = len(strs)
if n == 0: return ""
for i in range(len(strs[0])):
# 取第一个元素的值作为对比
tmp = strs[0][i]
for j in range(1,n):
# 如果已经达到最大长度 或 元素值不相同
if i == len(strs[j]) or strs[j][i] != tmp:
return strs[0][0:i]
return strs[0]
zip(*xx) 将同下标元素打包为一个元组,分别存入set进行验证即可
class Solution:
def longestCommonPrefix(self , strs: List[str]) -> str:
res = ''
# zip将同下标元素打包
for i in zip(*strs):
if len(set(i)) == 1:
res += i[0]
else:
break
return res
8. 最长的括号子串
class Solution:
def longestValidParentheses(self, s: str) -> int:
res = 0
# 记录上一次连续括号结束的位置
start = -1
st = []
for i in range(len(s)):
# 左括号入栈
if s[i] == "(":
st.append(i)
# 右括号
else:
# 如果右括号时栈为空,不合法,设置为结束位置
if len(st) == 0:
start = i
else:
# 弹出左括号
st.pop()
# 栈中还有左括号,说明右括号不够,减去栈顶位置就是长度
if len(st) != 0:
res = max(res, i - st[-1])
# 栈中没有括号,说明左右括号行号,减去上一次结束的位置就是长度
else:
res = max(res, i - start)
return res
9. 括号生成
class Solution:
def recursion(self, left: int, right: int, tmp: str, res: List[str], n: int):
if left == n and right == n:
res.append(tmp)
return
# 左括号
if left < n:
self.recursion(left + 1, right, tmp + "(", res, n)
# 右括号
if right < n and left > right:
self.recursion(left, right + 1, tmp + ")", res, n)
def generateParenthesis(self , n: int) -> List[str]:
res = []
tmp = ""
self.recursion(0, 0, tmp, res, n)
return res
10. 最小覆盖子串
class Solution:
# 检查是否覆盖(存在有小于0的说明未覆盖)
def check(self, map: dict()) -> bool:
for key, value in map.items():
if value < 0:
return False
return True
def minWindow(self , S: str, T: str) -> str:
count = len(S) + 1
map = dict()
for i in range(len(T)):
if T[i] in map:
map[T[i]] -= 1
else:
map[T[i]] = -1
slow = 0
fast = 0
left = -1
right = -1
while fast < len(S):
c = S[fast]
if c in map:
map[c] += 1
while self.check(map):
if count > fast -slow + 1:
count = fast - slow + 1
left = slow
right = fast
c = S[slow]
if c in map:
map[c] -= 1
# 窗口缩小
slow += 1
fast += 1
if left == -1: return ""
return S[left:right+1]
11. 重排字符串
import collections
class Solution:
def rearrangestring(s: str):
n = len(s)
# 排除特殊情况
if s is None or n <= 1:
return s
# 统计s中每个字符出现次数
count = collections.Counter(s)
maxCounter = max(count.values())
# 判断是否能够填充
if maxCounter > (n + 1)//2:
return ""
# 按字符出现次数
count = sorted(count.items(), key = lambda x: x[-1])
data = []
for k, v in count:
data += [k]*v
res = ["" for _ in range(len(s))]
res[::2] = data[:(n + 1) // 2]
res[1::2] = data[(n + 1) // 2:]
return "".join(res)
12. 字符串的排列(递归/回溯)
class Solution:
def recursion(self, res: List[str], strs: str, tmp: str, vis: List[int]):
if len(tmp) == len(strs):
res.append(tmp)
return
for i in range(len(strs)):
if vis[i] == 1:
continue
if i > 0 and strs[i-1] == strs[i] and not vis[i-1]:
continue
# 标记为使用过
vis[i] = 1
# 加入临时字符串
tmp += strs[i]
self.recursion(res, strs, tmp, vis)
# 回溯
vis[i] = 0
tmp = tmp[:-1]
def Permutation(self , str: str) -> List[str]:
str ="".join((lambda x:(x.sort(), x)[1])(list(str)))
vis = [0]*len(str)
res = []
tmp = ""
self.recursion(res, str, tmp, vis)
return res
13. 把数字翻译成字符串(DP)
class Solution:
def solve(self, nums: str) -> int:
# 排除0
if nums == "0":
return 0
# 排除只有一种可能的10 和 20
if nums == "10" or nums == "20":
return 1
# 当0的前面不是1或2时,无法译码,0种
for i in range(1, len(nums)):
if nums[i] == "0":
if nums[i - 1] != "1" and nums[i - 1] != "2":
return 0
# 辅助数组初始化为1
dp = [1 for i in range(len(nums) + 1)]
for i in range(2, len(nums) + 1):
# 在11-19,21-26之间的情况
if (nums[i - 2] == "1" and nums[i - 1] != "0") or (
nums[i - 2] == "2" and nums[i - 1] > "0" and nums[i - 1] < "7"):
dp[i] = dp[i - 1] + dp[i - 2]
else:
dp[i] = dp[i - 1]
return dp[len(nums)]
14. 数字字符串转化成IP地址(dfs+递归/回溯)
class Solution:
def restoreIpAddresses(self , s: str) -> List[str]:
def isNum(num):
# 排除以 0 开头的情况
if num and str(int(num)) == num and int(num) >= 0 and int(num) <= 255:
return True
else:
return False
res = []
for i in range(1,4):
w1 = s[:i]
if not isNum(w1):
continue
for j in range(i+1, i+4):
w2 = s[i:j]
if not isNum(w2):
continue
for k in range(j+1, j+4):
w3 = s[j:k]
w4 = s[k:]
if not isNum(w3) or not isNum(w4):
continue
res.append(w1 + '.' + w2 + '.' + w3 + '.' + w4)
return res
法二:
class Solution:
def __init__(self):
self.res = []
self.s = ""
self.nums = ""
# step表示第几个数字,index表示字符串下标
def dfs(self, step: int, index: int):
# 当前分割出的字符串
cur = ""
# 分割出了四个数字
if step == 4:
# 下标必须走到末尾
if index != len(self.s):
return
self.res.append(self.nums)
else:
i = index
# 最长遍历3位
while i < index + 3 and i < len(self.s):
cur += self.s[i]
# 转数字比较
num = int(cur)
temp = self.nums
# 不能超过255且不能有前导0
if num <= 255 and (len(cur) == 1 or cur[0] != "0"):
# 添加点
if step - 3 != 0:
self.nums += cur + "."
else:
self.nums += cur
# 递归查找下一个数字
self.dfs(step + 1, i + 1)
# 回溯
self.nums = temp
i += 1
def restoreIpAddresses(self, s: str) -> List[str]:
self.s = s
self.dfs(0, 0)
return self.res
15. 验证IP地址
class Solution:
def isIPv4(self, IP: str) -> bool:
s = IP.split('.')
if len(s) != 4:
return False
for i in range(len(s)):
# 每位不可缺省
if len(s[i]) == 0:
return False
# 1-3位数字,前缀不为0
if len(s[i]) > 3 or (len(s[i]) > 1 and s[i][0] == '0'):
return False
# 每位均为数字
for j in range(len(s[i])):
if s[i][j] < '0' or s[i][j] > '9':
return False
num = int(s[i])
if num < 0 or num > 255:
return False
return True
def isIPv6(self, IP: str) -> bool:
s = IP.split(':')
if len(s) != 8:
return False
for i in range(len(s)):
# 每位不可缺省
if len(s[i]) == 0 or len(s[i]) > 4:
return False
for j in range(len(s[i])):
if not (s[i][j].isdigit() or s[i][j] >= 'a' and s[i][j] <= 'f' or s[i][j] >= 'A' and s[i][j] <= 'F'):
return False
return True
def solve(self , IP: str) -> str:
if len(IP) == 0: return "Neither"
if self.isIPv4(IP): return "IPv4"
if self.isIPv6(IP): return "IPv6"
return "Neither"
正则表达式法:
import re
class Solution:
def solve(self, IP: str) -> str:
# 0-255,前缀不为0
ipv4 = "(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])"
# 0-9 a-f A-F,位数为1-4位
ipv6 = "([0-9a-fA-F]{1,4}\:){7}([0-9a-fA-F]{1,4})$"
ipv4 = re.compile(ipv4)
ipv6 = re.compile(ipv6)
# 正则匹配函数
if ipv4.match(IP):
return "IPv4"
if ipv6.match(IP):
return "IPv6"
return "Neither"
16. 正则表达式匹配(DP)
class Solution:
def match(self, str: str, pattern: str) -> bool:
n1 = len(str)
n2 = len(pattern)
# dp[i][j]表示str前i个字符和pattern前j个字符是否匹配
dp = [[False] * (n2 + 1) for i in range(n1 + 1)]
# 两个都为空串自然匹配
dp[0][0] = True
# 初始化str为空的情况,字符串下标从1开始
for i in range(2, n2 + 1):
# 可以让自己前面个字符重复0次
if pattern[i - 1] == "*":
# 与再前一个能够匹配空串有关
dp[0][i] = dp[0][i - 2]
# 遍历str每个长度
for i in range(1, n1 + 1):
# 遍历pattern每个长度
for j in range(n2 + 1):
# 当前字符不为*,用.去匹配或者字符直接相同
if pattern[j - 1] != "*" and (
pattern[j - 1] == "." or pattern[j - 1] == str[i - 1]
):
dp[i][j] = dp[i - 1][j - 1]
# 当前的字符为*
elif j >= 2 and pattern[j - 1] == "*":
# 若是前一位为.或者前一位可以与这个数字匹配
if pattern[j - 2] == "." or pattern[j - 2] == str[i - 1]:
# 转移情况
dp[i][j] = dp[i - 1][j] or dp[i][j - 2]
else:
# 不匹配
dp[i][j] = dp[i][j - 2]
return dp[n1][n2]
17. 比较版本号
class Solution:
def compare(self , version1: str, version2: str) -> int:
v1 = version1.split('.')
v2 = version2.split('.')
for i in range(max(len(v1), len(v2))):
num1 = int(v1[i]) if i < len(v1) else 0
num2 = int(v2[i]) if i < len(v2) else 0
if num1 > num2:
return 1
elif num1 < num2:
return -1
return 0
18. 大数加法
class Solution:
def solve(self , s: str, t: str) -> str:
if len(s) == 0: return t
if len(t) == 0: return s
# s作为长
if len(s) < len(t): s,t = t,s
# 进位标志
carry = 0
for i in range(len(s)-1,-1,-1):
tmp = ord(s[i]) - ord('0') + carry
j = i - len(s) + len(t)
if j >= 0:
tmp += ord(t[j]) - ord('0')
carry = int(tmp / 10)
tmp %= 10
s = s[:i] + chr(tmp + ord('0')) + s[i+1:]
if carry == 1: s = '1' + s
return s