前言
繼續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