前言
继续leetcode刷题生涯
这里记录的都是笔者觉得有点意思的做法
参考了好几位大佬的题解,尤其是powcai大佬和labuladong大佬,感谢各位大佬
391. 完美矩形
class Solution:
def isRectangleCover(self, rectangles: List[List[int]]) -> bool:
# 保存所有矩形的四个点
lookup = set()
# 最大矩形的 左下角 右上角
x1 = float("inf")
y1 = float("inf")
x2 = float("-inf")
y2 = float("-inf")
area = 0
for x, y, s, t in rectangles:
x1 = min(x1, x)
y1 = min(y1, y)
x2 = max(x2, s)
y2 = max(y2, t)
area += (t - y) * (s - x)
# 每个矩形的四个点
for item in [(x, y), (x, t), (s, y), (s, t)]:
if item not in lookup:
lookup.add(item)
else:
lookup.remove(item)
# 只剩下四个点并且是最大矩形的左下角和右上角
if len(lookup) != 4 or (x1, y1) not in lookup or (x1, y2) not in lookup or (x2, y1) not in lookup or (x2, y2) not in lookup:
return False
# 面积是否满足
return (x2 - x1) * (y2 - y1) == area
392. 判断子序列
class Solution:
def isSubsequence(self, s: str, t: str) -> bool:
i = 0
j = 0
while i < len(s) and j < len(t):
if s[i] == t[j]:
i += 1
j += 1
else:
j += 1
return i == len(s)
393. UTF-8 编码验证
class Solution:
def validUtf8(self, data: List[int]) -> bool:
if not data: return False
cnt = 0
for d in data:
if cnt == 0:
if d >> 5 == 0b110:
cnt = 1
elif d >> 4 == 0b1110:
cnt = 2
elif d >> 3 == 0b11110:
cnt = 3
elif d >> 7 != 0:
return False
else:
if d >> 6 != 0b10: return False
cnt -= 1
return cnt == 0
394. 字符串解码
class Solution:
def decodeString(self, s: str) -> str:
pos = 0
def helper():
nonlocal pos
num = 0
word = ""
while pos < len(s):
cur = s[pos]
if cur == '[':
pos += 1
curStr = helper()
word += num * curStr
num = 0
elif cur.isdigit():
num = num * 10 + int(cur)
elif cur == ']':
return word
else:
word += cur
pos += 1
return word
return helper()
395. 至少有K个重复字符的最长子串
class Solution:
def longestSubstring(self, s: str, k: int) -> int:
if len(s) < k:
return 0
# 找个字符串个数最少的字符
t = min(set(s), key=s.count)
# 最少字符的个数都大于等于k
if s.count(t) >= k:
return len(s)
return max(self.longestSubstring(a,k) for a in s.split(t))
396. 旋转函数
# F(k)=F(k−1)+sum(A)−len(A)∗A[len(A)−k]
class Solution:
def maxRotateFunction(self, A: List[int]) -> int:
n = len(A)
cur = sum(A[i] * i for i in range(n))
_sum = sum(A)
res = cur
for i in range(1, n):
cur = _sum - n * A[-i] + cur
res = max(res, cur)
return res
397. 整数替换
# 规律
class Solution:
def integerReplacement(self, n: int) -> int:
step = 0
while n > 1:
if n & 1 == 0: n >>= 1
elif (n + 1) % 4 == 0 and n != 3: n += 1
else:
n -= 1
step += 1
return step
# 递归,这里很妙的是带记忆,这个函数笔者之前都没接触过
from functools import lru_cache
class Solution:
@lru_cache
def integerReplacement(self, n: int) -> int:
if n == 1:
return 0
if n % 2 == 0:
return self.integerReplacement(n // 2) + 1
else:
return min(self.integerReplacement(n + 1), self.integerReplacement(n - 1)) + 1
398. 随机数索引
# 蓄水池采样
import random
class Solution:
def __init__(self, nums):
self.nums = nums
def pick(self, target: int) -> int:
count = 0
res = -1
for i in range(len(self.nums)):
if self.nums[i] == target:
if random.randint(0, count) < 1: # 以某一概率(1/count)抽样
res = i
count += 1
return res
399. 除法求值
class Solution:
def calcEquation(self, equations: List[List[str]], values: List[float], queries: List[List[str]]) -> List[float]:
# 构造图,equations的第一项除以第二项等于value里的对应值,第二项除以第一项等于其倒数
graph = {}
for (x, y), v in zip(equations, values):
if x in graph:
graph[x][y] = v
else:
graph[x] = {y: v}
if y in graph:
graph[y][x] = 1 / v
else:
graph[y] = {x: 1 / v}
# dfs找寻从s到t的路径并返回结果叠乘后的边权重即结果
def dfs(s, t) -> int:
if s not in graph:
return -1
if t == s:
return 1
for node in graph[s].keys():
if node == t:
return graph[s][node]
elif node not in visited:
visited.add(node) # 添加到已访问避免重复遍历
v = dfs(node, t)
if v != -1:
return graph[s][node] * v
return -1
# 逐个计算query的值
res = []
for qs, qt in queries:
visited = set()
res.append(dfs(qs, qt))
return res
400. 第N个数字
class Solution:
def findNthDigit(self, n: int) -> int:
if n < 10: return n
# 个数
num = 9
# 位数
digit = 1
while n - num * digit > 0:
# 个数 * 位数 == 总数字个数
n -= num * digit
num *= 10
digit += 1
a, b = divmod(n - 1, digit)
return int(str(10 ** (digit - 1) + a)[b])