前言
继续leetcode刷题生涯
这里记录的都是笔者觉得有点意思的做法
参考了好几位大佬的题解,尤其是powcai大佬和labuladong大佬,感谢各位大佬
432. 全 O(1) 的数据结构
# 双向链表
# 定义双向节点
class Node:
def __init__(self, cnt):
self.cnt = cnt
# 记录该cnt(计数)下key包括哪些
self.keySet = set()
# 前后指针
self.prev = None
self.next = None
class AllOne:
def __init__(self):
"""
Initialize your data structure here.
"""
# 记录头尾 便于求最小值最大值
self.head = Node(float("-inf"))
self.tail = Node(float("inf"))
# 首尾相连
self.head.next = self.tail
self.tail.prev = self.head
# 个数对应的节点
self.cntKey = {}
# key 对应的个数
self.keyCnt = {}
def inc(self, key: str) -> None:
"""
Inserts a new key <Key> with value 1. Or increments an existing key by 1.
"""
if key in self.keyCnt:
self.changeKey(key, 1)
else:
self.keyCnt[key] = 1
# 说明没有计数为1的节点,在self.head后面加入
if self.head.next.cnt != 1:
self.addNodeAfter(Node(1), self.head)
self.head.next.keySet.add(key)
self.cntKey[1] = self.head.next
def dec(self, key: str) -> None:
"""
Decrements an existing key by 1. If Key's value is 1, remove it from the data structure.
"""
if key in self.keyCnt:
cnt = self.keyCnt[key]
if cnt == 1:
self.keyCnt.pop(key)
self.removeFromNode(self.cntKey[cnt], key)
else:
self.changeKey(key, -1)
def getMaxKey(self) -> str:
"""
Returns one of the keys with maximal value.
"""
return "" if self.tail.prev == self.head else next(iter(self.tail.prev.keySet))
def getMinKey(self) -> str:
"""
Returns one of the keys with Minimal value.
"""
return "" if self.head.next == self.tail else next(iter(self.head.next.keySet))
# key加1或者减1
def changeKey(self, key, offset):
cnt = self.keyCnt[key]
self.keyCnt[key] = cnt + offset
curNode = self.cntKey[cnt]
newNode = None
if cnt + offset in self.cntKey:
newNode = self.cntKey[cnt + offset]
else:
newNode = Node(cnt + offset)
self.cntKey[cnt + offset] = newNode
self.addNodeAfter(newNode, curNode if offset == 1 else curNode.prev)
newNode.keySet.add(key)
self.removeFromNode(curNode, key)
# 在prevNode后面加入newNode
def addNodeAfter(self, newNode, prevNode):
newNode.prev = prevNode
newNode.next = prevNode.next
prevNode.next.prev = newNode
prevNode.next = newNode
# 在curNode删除key
def removeFromNode(self, curNode, key):
curNode.keySet.remove(key)
if len(curNode.keySet) == 0:
self.removeNodeFromList(curNode)
self.cntKey.pop(curNode.cnt)
# 删掉curNode节点
def removeNodeFromList(self, curNode):
curNode.prev.next = curNode.next
curNode.next.prev = curNode.prev
curNode.next = None
curNode.prev = None
433. 最小基因变化
# 双向dfs
class Solution:
def minMutation(self, start: str, end: str, bank: List[str]) -> int:
if end not in bank: return -1
start_set = {start}
end_set = {end}
bank = set(bank)
length = 0
change_map = {'A': 'TCG', 'T': 'ACG', 'C': 'ATG', 'G': 'ATC'}
while start_set:
length += 1
new_set = set()
for node in start_set:
for i, s in enumerate(node):
for c in change_map[s]:
new = node[:i] + c + node[i + 1:]
if new in end_set:
return length
if new in bank:
new_set.add(new)
bank.remove(new)
start_set = new_set
if len(end_set) < len(start_set):
start_set, end_set = end_set, start_set
return -1
434. 字符串中的单词数
class Solution:
def countSegments(self, s: str) -> int:
return len(s.split())
435. 无重叠区间
# 贪心
class Solution:
def eraseOverlapIntervals(self, intervals: List[List[int]]) -> int:
intervals.sort(key=lambda x: x[1])
cur_end = float("-inf")
num = 0
for start, end in intervals:
if start >= cur_end:
num += 1
cur_end = end
return len(intervals) - num
436. 寻找右区间
# 双指针
class Solution:
def findRightInterval(self, intervals: List[List[int]]) -> List[int]:
n = len(intervals)
intervals = [tuple(interval) for interval in intervals]
res = [-1] * n
loc = {}
for idx, val in enumerate(intervals):
loc[val] = idx
left_sort = sorted(intervals)
right_sort = sorted(intervals, key=lambda x: x[1])
i = 0
j = 0
while i < n:
while j < n and right_sort[j][1] <= left_sort[i][0]:
res[loc[right_sort[j]]] = loc[left_sort[i]]
j += 1
else:
i += 1
return res
437. 路径总和 III
# 前缀和
class Solution:
def pathSum(self, root: TreeNode, _sum: int) -> int:
from collections import defaultdict
prefix = defaultdict(int)
# 前缀和的个数
prefix[0] = 1
res = 0
def dfs(root, cur):
nonlocal res
if not root: return
cur += root.val
target = cur - _sum
res += prefix[target]
prefix[cur] += 1
dfs(root.left, cur)
dfs(root.right, cur)
# 回溯
prefix[cur] -= 1
dfs(root, 0)
return res
438. 找到字符串中所有字母异位词
# 滑动窗口
class Solution:
def findAnagrams(self, s: str, p: str) -> List[int]:
# 记录p, s字母个数
p_count = [0] * 26
s_count = [0] * 26
res = []
for a in p:
p_count[ord(a) - 97] += 1
left = 0
for right in range(len(s)):
if right < len(p) - 1:
s_count[ord(s[right]) - 97] += 1
continue
# 窗口加一个, 减一个,维护长度为len(p)的长度
s_count[ord(s[right]) - 97] += 1
if p_count == s_count:
res.append(left)
s_count[ord(s[left]) - 97] -= 1
left += 1
return res
440. 字典序的第K小数字
# 十叉树
class Solution:
def findKthNumber(self, n: int, k: int) -> int:
def cal_steps(n, n1, n2):
step = 0
while n1 <= n:
step += min(n2, n + 1) - n1
n1 *= 10
n2 *= 10
return step
res = 1
k -= 1
while k > 0:
steps = cal_steps(n, res, res + 1)
if steps <= k:
k -= steps
res += 1
else:
k -= 1
res *= 10
return res