Skip to content

Commit 2f2357c

Browse files
update
1 parent 0b6b67c commit 2f2357c

12 files changed

+625
-80
lines changed

Diff for: Array/LC56MergeIntervals.py

+17-14
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
from typing import List
2-
3-
class Solution:
4-
def merge(self, intervals: List[List[int]]) -> List[List[int]]:
5-
ret = []
6-
intervals = sorted(intervals) # sorted on first element of inner list
7-
cur_left, cur_right = intervals[0][0], intervals[0][1]
8-
for i in range(1, len(intervals)):
9-
if intervals[i][0] > cur_right:
10-
ret.append([cur_left, cur_right])
11-
cur_left, cur_right = intervals[i][0], intervals[i][1]
12-
else:
13-
cur_right = max(cur_right, intervals[i][1])
14-
ret.append([cur_left, cur_right]) # last interval needs to process outside of for loop
15-
return ret
2+
'''
3+
Time o(nlogn) for sorting, Space o(1)
4+
if current interval does not overlap with the previous: append previous one to result.
5+
else, if overlap: update previous ending to be max(current, previous)
6+
'''
7+
def merge(intervals: List[List[int]]) -> List[List[int]]:
8+
ret = []
9+
intervals = sorted(intervals) # sorted on first element of inner list
10+
prev_left, prev_right = intervals[0][0], intervals[0][1]
11+
for i in range(1, len(intervals)):
12+
if intervals[i][0] > prev_right:
13+
ret.append([prev_left, prev_right])
14+
prev_left, prev_right = intervals[i][0], intervals[i][1]
15+
else:
16+
prev_right = max(prev_right, intervals[i][1]) # 注意这里只更新right 不能append. 后面可能还有重叠的intervals
17+
ret.append([prev_left, prev_right]) # last interval needs to process outside of for loop
18+
return ret

Diff for: BFS/LC1091ShortestPathInBinaryMatrix.py

+94-21
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,96 @@
1-
from typing import List
2-
from collections import deque
1+
from typing import List, collections
32

4-
class Solution:
5-
def shortestPathBinaryMatrix(self, grid: List[List[int]]) -> int:
6-
size = len(grid) - 1
7-
if grid[0][0] == 1 or grid[size][size] == 1: return -1
8-
if len(grid) == 1: return 1
3+
# 解法1: bfs. 直接修改输入 优化空间复杂度. T(m*n) S(n*n) 每个格子最多处理1次
4+
def shortestPathBinaryMatrix(grid: List[List[int]]) -> int:
5+
size = len(grid) - 1
6+
if grid[0][0] == 1 or grid[size][size] == 1:
7+
return -1
8+
if len(grid) == 1: # n * n 只有1个格子
9+
return 1
10+
11+
dx = [0, 1, 0, -1, 1, 1, -1, -1]
12+
dy = [1, 0, -1, 0, 1, -1, 1, -1]
13+
step = 0
14+
queue = collections.deque([(0,0)])
15+
grid[0][0] = 1 # 把走过的路变成obsticles 节省用visited
16+
while queue:
17+
step += 1 # 这里加step 之后不用加了
18+
for i in range(len(queue)):
19+
x, y = queue.popleft()
20+
if x == size and y == size:
21+
return step
22+
for d in range(8):
23+
newx = x + dx[d]
24+
newy = y + dy[d]
25+
if 0 <= newx <= size and 0 <= newy <= size and grid[newx][newy] == 0:
26+
queue.append((newx, newy))
27+
grid[newx][newy] = 1 # mark visited
28+
return -1
929

10-
queue, level = deque([(0,0)]), 2 # at least two cells: start and end cells
11-
while queue:
12-
for _ in range(len(queue)):
13-
coord_y, coord_x = queue.popleft()
14-
for (dx,dy) in ((0, -1), (-1, -1), (-1, 0), (-1, 1), (0, 1), (1, 1), (1, 0), (1, -1)):
15-
nx, ny = coord_x + dx, coord_y + dy
16-
if nx < 0 or ny < 0 or nx > size or ny > size or grid[ny][nx] != 0: # filter out unfeasible cell
17-
continue
18-
if ny == size and nx == size: # find end cell
19-
return level
20-
grid[ny][nx] = 2 # act as a visted set
21-
queue.append((ny, nx)) # enqueue a feasible new cell
22-
level += 1
23-
return -1
30+
# variant: return one shorest path.
31+
# bfs的过程中 用dict[(nx, ny)] = (x, y)表示从(x,y)走到的(nx,ny). 在终点back trace回去.
32+
def oneShortestPathBinaryMatrix(grid: List[List[int]]) -> List[tuple[int]]:
33+
size = len(grid) - 1
34+
if grid[0][0] == 1 or grid[size][size] == 1:
35+
return []
36+
if len(grid) == 1: # n * n 只有1个格子
37+
return [(0, 0)]
38+
39+
dx = [0, 1, 0, -1, 1, 1, -1, -1]
40+
dy = [1, 0, -1, 0, 1, -1, 1, -1]
41+
step = 0
42+
queue = collections.deque([(0,0)])
43+
trace = collections.defaultdict(tuple)
44+
grid[0][0] = 1 # 把走过的路变成obsticles 节省用visited
45+
while queue:
46+
step += 1 # 这里加step 之后不用加了
47+
for _ in range(len(queue)):
48+
x, y = queue.popleft()
49+
if x == size and y == size:
50+
ret = collections.deque()
51+
ret.appendleft((x, y))
52+
while (x, y) != (0 ,0):
53+
(x, y) = trace[(x, y)]
54+
ret.appendleft((x, y))
55+
return ret
56+
for d in range(8):
57+
newx = x + dx[d]
58+
newy = y + dy[d]
59+
if 0 <= newx <= size and 0 <= newy <= size and grid[newx][newy] == 0:
60+
queue.append((newx, newy))
61+
trace[(newx, newy)] = (x, y)
62+
grid[newx][newy] = 1 # mark visited
63+
return []
64+
65+
# variant: return any one path, not necessary shorest.
66+
# 解法:DFS.
67+
def onePathBinaryMatrix(grid: List[List[int]]) -> List[tuple[int]]:
68+
if not grid or grid[0][0] != 0 or grid[len(grid) - 1][len(grid[0]) - 1] != 0:
69+
return -1
70+
tmp = [(0,0)]
71+
ret = []
72+
grid[0][0] = 1
73+
dfs(ret, tmp, grid, 0, 0)
74+
return ret
75+
76+
def dfs(ret, tmp, grid, x, y):
77+
if len(ret) > 0: # 找到一个解
78+
return
79+
if x == len(grid) - 1 and y == len(grid[0]) - 1:
80+
ret.append(tmp[:]) # 这里要深拷贝
81+
return
82+
83+
dx = [0, 1, 0, -1, 1, 1, -1, -1]
84+
dy = [1, 0, -1, 0, -1, 1, 1, -1]
85+
for i in range(8):
86+
nx, ny = x + dx[i], y + dy[i]
87+
if 0 <= nx <= len(grid) - 1 and 0 <= ny <= len(grid[0]) - 1 and grid[nx][ny] == 0:
88+
grid[nx][ny] = 1 # mark visted
89+
tmp.append((nx, ny)) # add trace
90+
dfs(ret, tmp, grid, nx, ny)
91+
tmp.pop() # restore status
92+
grid[nx][ny] = 0
93+
94+
grid0 = [[0,0,0],[1,1,0],[1,1,0]]
95+
grid1 = [[0,1],[1,0]]
96+
print(oneShortestPathBinaryMatrix(grid1))

Diff for: BinarySearch/LC162FindPeakElement.py

+15-13
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
from typing import List
2+
'''
3+
A peak element is an element that is strictly greater than its neighbors.
4+
You may imagine that nums[-1] = nums[n] = -∞
5+
'''
6+
def findPeakElement(nums: List[int]) -> int: # 返回peak item的index
7+
if len(nums) == 1:
8+
return 0
29

3-
class Solution:
4-
def findPeakElement(self, nums: List[int]) -> int:
5-
if len(nums) == 1:
6-
return 0
7-
8-
left, right = 0, len(nums) - 1
9-
while left < right:
10-
mid = (left + right) // 2
11-
if nums[mid] > nums[mid + 1]: # ans in [left, mid]
12-
right = mid
13-
else:
14-
left = mid + 1
15-
return right
10+
left, right = 0, len(nums) - 1
11+
while left < right:
12+
mid = (left + right) // 2
13+
if nums[mid] > nums[mid + 1]: # ans in [left, mid]
14+
right = mid
15+
else:
16+
left = mid + 1
17+
return right

Diff for: DataStructure/LC346MovingAverageFromDataStream.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
class MovingAverage:
44

55
def __init__(self, size: int):
6-
self.queue = collections.queue()
7-
self.size = size
8-
self.total = 0
6+
self.queue = collections.deque()
7+
self.size = size # 队列目标长度(非实际长度)
8+
self.total = 0 # 队列内数值之和
99

1010

1111
def next(self, val: int) -> float:

Diff for: Meta/LC1 Two Sum.py

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
from typing import List, collections
2+
# Meta variant 1: return True or False
3+
def has_two_sum(nums: List[int], target) -> bool:
4+
if not nums:
5+
return False
6+
seen_set = set()
7+
for num in nums:
8+
other = target - num
9+
if other in seen_set:
10+
return True
11+
seen_set.add(num)
12+
return False
13+
14+
# Meta variant 2. Given list of pairs[[x1, x2], ...] and a target,
15+
# return number of unique pairs [a1, a2] and [b1, b2] where a1+b1=target and a2+b2=target
16+
# numbers are limited to digits 0-9. same pair can't be used with itself.
17+
# 思路:linear scan + dict. dict记录扫描过的pair出现的次数.每次用当前pair去检查dict里是否有加起来等于target的pairs
18+
def unique_pairs(pairs: List[List[int]], target: int) -> int:
19+
if not pairs:
20+
return 0
21+
pair_to_freq = collections.defaultdict(int)
22+
ret = 0
23+
for pair in pairs:
24+
first, second = target - pair[0], target - pair[1]
25+
if (first, second) in pair_to_freq:
26+
ret += pair_to_freq[(first, second)]
27+
pair_to_freq[(pair[0], pair[1])] += 1 # 注意这里用pair而非(first,second)更新dict
28+
return ret
29+
# test
30+
pairs = [[3,4], [1,9], [3,4], [2,1],[9,1], [9,1], [7,6], [1,9]]
31+
target = 10
32+
print(unique_pairs(pairs, target))
33+
34+
# leetcode version.
35+
def twoSum(nums: List[int], target: int) -> List[int]:
36+
if not nums: return [-1, -1]
37+
dict = {} # 存num和对应的下标
38+
for i in range(len(nums)):
39+
if target - nums[i] not in dict:
40+
dict[nums[i]] = i
41+
else:
42+
return [i, dict[target - nums[i]]]

Diff for: Meta/LC138 Copy List with Random Pointer.py

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
2+
class Node:
3+
def __init__(self, x: int, next: 'Node' = None, random: 'Node' = None):
4+
self.val = int(x)
5+
self.next = next
6+
self.random = random
7+
8+
def copyRandomList(head: 'Optional[Node]') -> 'Optional[Node]':
9+
if not head:
10+
return None
11+
dummy = Node(0)
12+
dummy.next = head
13+
14+
# copy node. copy placed at the next of original
15+
# dummy -> o1->c1->o2->c2-> ...
16+
while head:
17+
copy = Node(head.val)
18+
copy.next = head.next
19+
head.next = copy
20+
head = head.next.next
21+
22+
# copy random
23+
head = dummy.next
24+
while head and head.next: # must have head.next
25+
if head.random: # some random is null
26+
head.next.random = head.random.next # head.random的next是h.random的copy
27+
head = head.next.next # 已经插入 要走两步
28+
29+
# split
30+
head = dummy.next.next
31+
res = dummy.next.next
32+
while head and head.next:
33+
tmp = head.next.next
34+
head.next = tmp
35+
head = head.next # 已经去掉原来的head.next 只走一步
36+
return res

Diff for: Meta/LC146 LRU Cache.py

+114
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
from typing import collections
2+
3+
# Meta variant: 多实现两个接口 del(key) -> bool, last() -> int
4+
# last()返回most recent used value if there's.
5+
# get, put, del run O(1) average, last runs O(1)
6+
# no capacity requiement: no limitation on capacity
7+
class Node:
8+
def __init__(self, key, value):
9+
self.key = key
10+
self.value = value
11+
self.next = None
12+
self.prev = None
13+
class LRU_cache_v1:
14+
def __init__(self): # 注意没有capacity限制了
15+
self.head = Node(0,0)
16+
self.tail = Node(-1,-1)
17+
self.head.next = self.tail
18+
self.tail.prev = self.head
19+
self.val_to_ref = collections.defaultdict(Node)
20+
21+
def reconnect_nodes(self, node: Node): # helper func
22+
prev = node.prev
23+
next = node.next
24+
prev.next = next
25+
next.prev = prev
26+
27+
def move_to_end(self, node: Node):
28+
before = self.tail.prev
29+
before.next = node
30+
node.prev = before
31+
32+
node.next = self.tail
33+
self.tail.prev = node
34+
35+
def get(self, key: int) -> int:
36+
if key not in self.val_to_ref:
37+
return -1
38+
cur = self.val_to_ref[key]
39+
val = cur.value
40+
self.reconnect_nodes(cur)
41+
self.move_to_end(cur)
42+
return val
43+
44+
def put(self, key:int, val:int):
45+
if key in self.val_to_ref: # 之前存在 先删掉 再插入新的
46+
cur = self.val_to_ref[key]
47+
self.reconnect_nodes(cur)
48+
del self.val_to_ref[key]
49+
50+
cur = Node(key, val)
51+
self.val_to_ref[key] = cur
52+
self.move_to_end(cur)
53+
54+
def delelte_key(self, key:int) -> bool:
55+
if key not in self.val_to_ref:
56+
return False
57+
remove = self.val_to_ref[key]
58+
self.reconnect_nodes(remove)
59+
del self.val_to_ref[key]
60+
return True
61+
62+
def last(self) -> int:
63+
if self.tail.prev == self.head: # cache为空
64+
return -1
65+
return self.tail.prev.value # tail之前的节点一直是most recent used one
66+
67+
# leetcode version
68+
class LRUCache:
69+
def __init__(self, capacity: int):
70+
self.capacity = capacity
71+
# 创建两个dummy, 一个head一个tail
72+
self.head = Node(0, 0)
73+
self.tail = Node(0, 0)
74+
self.head.next = self.tail
75+
self.tail.prev = self.head
76+
77+
self.dict = {}
78+
79+
def get(self, key: int) -> int:
80+
if key not in self.dict:
81+
return -1
82+
else:
83+
node = self.dict[key]
84+
self.remove(node)
85+
self.add(node)
86+
return node.value
87+
88+
def put(self, key: int, value: int) -> None:
89+
newnode = Node(key, value) #注意这里的处理 需要先new一个新node
90+
if key in self.dict: # 这里要remove oldnode, add newnode
91+
oldnode = self.dict[key]
92+
self.remove(oldnode)
93+
self.add(newnode)
94+
self.dict[key] = newnode
95+
else:
96+
self.add(newnode) #每次的add/remove dict里面都要一起
97+
self.dict[key] = newnode
98+
if len(self.dict) > self.capacity:
99+
toRemove = self.head.next
100+
self.remove(toRemove)
101+
del self.dict[toRemove.key]
102+
103+
# head -> 0 -> 1 -> tail
104+
#只需要用到add to tail(this is the dummy tail node)
105+
def add(self, node):
106+
tailpre = self.tail.prev
107+
tailpre.next = node
108+
node.prev = tailpre
109+
node.next = self.tail
110+
self.tail.prev = node
111+
112+
def remove(self, node):
113+
node.prev.next = node.next
114+
node.next.prev = node.prev

0 commit comments

Comments
 (0)