def findShortestWay(self, A, ball, hole): ball, hole = tuple(ball), tuple(hole) R, C = len(A), len(A[0]) def neighbors(r, c): for dr, dc, di in [(-1, 0, 'u'), (0, 1, 'r'), (0, -1, 'l'), (1, 0, 'd')]: cr, cc, dist = r, c, 0 while (0 <= cr + dr < R and 0 <= cc + dc < C and not A[cr+dr][cc+dc]): cr += dr cc += dc dist += 1 if (cr, cc) == hole: break yield (cr, cc), di, dist pq = [(0, '', ball)] seen = set() while pq: dist, path, node = heapq.heappop(pq) if node in seen: continue if node == hole: return path seen.add(node) for nei, di, nei_dist in neighbors(*node): heapq.heappush(pq, (dist+nei_dist, path+di, nei) ) return "impossible"
def slidingPuzzle(self, board): self.goal = [[1,2,3], [4,5,0]] self.score = [0] * 6 self.score[0] = [[3, 2, 1], [2, 1, 0]] self.score[1] = [[0, 1, 2], [1, 2, 3]] self.score[2] = [[1, 0, 1], [2, 1, 2]] self.score[3] = [[2, 1, 0], [3, 2, 1]] self.score[4] = [[1, 2, 3], [0, 1, 2]] self.score[5] = [[2, 1, 2], [1, 0, 1]] heap = [(0, 0, board)] closed = [] while len(heap) > 0: node = heapq.heappop(heap) if node[2] == self.goal: return node[1] elif node[2] in closed: continue else: for next in self.get_neighbors(node[2]): if next in closed: continue heapq.heappush(heap, (node[1] + 1 + self.get_score(next), node[1] + 1, next)) closed.append(node[2]) return -1
def top(mat, k): m, n = len(mat), len(mat[0]) h = [] temp = [sum(row[0] for row in mat)] + [0] * m temp = tuple(temp) h = [temp] check = set(tuple([0] * m)) count = 0 while h: #print(h, h[0]) t = heapq.heappop(h) count += 1 s = t[0] if count == k: return s cur = list(t[1:]) for i, v in enumerate(cur): if v < n - 1: cur[i] += 1 if tuple(cur) not in check: check.add(tuple(cur)) heapq.heappush( h, tuple([ t[0] + mat[i - 1][cur[i]] - mat[i - 1][cur[i] - 1] ] + cur)) cur[i] -= 1
def dijkstra_heap(s, edge, n): """ ヒープ式高速ダイクストラ n:頂点数 0-indexed edges[頂点番号]=[(cost,to)] """ # 始点sから各頂点への最短距離 d = [INF] * n used = [True] * n # True:未確定 d[s] = 0 used[s] = False edgelist = [] frm = [-1] * n for a, b in edge[s]: heapq.heappush(edgelist, (a * (10**6) + b, -1)) while len(edgelist): minedge = heapq.heappop(edgelist) froom = minedge[1] minedge = minedge[0] # まだ使われてない頂点の中から最小の距離のものを探す if not used[minedge % (10**6)]: continue v = minedge % (10**6) d[v] = minedge // (10**6) frm[v] = froom used[v] = False for e in edge[v]: if used[e[1]]: heapq.heappush(edgelist, ((e[0] + d[v]) * (10**6) + e[1], v)) return (d, frm)
def minMeetingRooms(self, intervals): if not intervals: return 0 # heap rooms = [] intervals.sort(key=lambda x: x[0]) # heap is storing the end time. heapq.heappush(rooms, intervals[0][1]) for interval in intervals[1:]: # room[0] means the top of the heap # if both pop and push executed. that means no room. If pop not excuted, that menas new room added if rooms[0] <= interval[0]: heapq.heappop(rooms) heapq.heappush(rooms, interval[1]) return len(rooms)
def minSetSize(self, arr: List[int]) -> int: count_dict = Counter(arr) # O(n) min_size = 1 heap = [] total = 0 max_count = max(count_dict.values()) for key, value in count_dict.items(): # O(n) heapq.heappush(heap, (-value, key)) total = (-1 * heap[0][0]) while total < len(arr) // 2: # O(n/2) min_size += 1 heapq.heappop(heap) total += (-1 * heap[0][0]) return min_size
def largestSumAfterKNegations(self, A: List[int], K: int) -> int: _sum = sum(A) heapq.heapify(A) while K > 0: curmin = heapq.heappop(A) heapq.heappush(A, -curmin) K -= 1 _sum += -curmin * 2 return _sum
def findCheapestPrice(self, n, flights, src, dst, k): f = collections.defaultdict(dict) for a, b, p in flights: f[a][b] = p heap = [(0, src, k + 1)] while heap: p, i, k = heapq.heappop(heap) if i == dst: return p if k > 0: for j in f[i]: heapq.heappush(heap, (p + f[i][j], j, k - 1)) return -1
def frequencySort(self, s: str) -> str: counter = Counter(s) heap = [] for key,value in counter.items(): heapq.heappush(heap, (-value, key)) result = [] while heap: value, char = heapq.heappop(heap) result.append(-value * char) return "".join(result)
def mergeKLists(self, lists: List[Optional[ListNode]]) -> Optional[ListNode]: hp = [(node.val, i, node) for i, node in enumerate(lists) if node] heapq.heapify(hp) counter = len(lists) dummy_head = curr = ListNode() while hp: _, _, node = heapq.heappop(hp) curr.next = node if node.next: heapq.heappush(hp, (node.next.val, counter, node.next)) counter += 1 curr = curr.next return dummy_head.next
def reorganizeString2(self, S): pq = [(-S.count(x), x) for x in set(S)] heapq.heapify(pg) if any(-ct > (len(s) + 1) / 2 for ct, x in pg): return "" ans = [] while len(pq) >= 2: freq1, ch1 = heapq.heappop(pq) freq2, ch2 = heapq.heappop(pq) #This code turns out to be superfluous, but explains what is happening #if not ans or ch1 != ans[-1]: # ans.extend([ch1, ch2]) #else: # ans.extend([ch2, ch1]) ans.extend([ch1, ch2]) if freq1 + 1: # notice the freq is negative here... heapq.heappush(pq, (freq1 + 1, ch1)) if freq2 + 1: heapq.heappush(pq, (freq2 + 1, ch2)) # second part is for single pair left in the heapq return "".join(ans) + (pq[0][1] if pq else '')
def maximumMinimumPath(self, A: List[List[int]]): d = [(0, 1), (1, 0), (0, -1), (-1, 0)] row, col = len(A), len(A[0]) maxHeap = [(-A[0][0], 0, 0)] visited = [[0 for _ in range(col)] for _ in range(row)] while maxHeap: curr, x, y = heapq.heappop(maxHeap) if x == row - 1 and y == col - 1: return -curr for dx, dy in d: nx, ny = x + dx, y + dy if 0 <= nx < row and 0 <= ny < col and not visited[nx][ny]: visited[nx][ny] = 1 heapq.heappush(maxHeap, (max(curr, -A[nx][ny]), nx, ny)) return -1
def networkDelayTime(self, times, N, K): graph = collections.defaultdict(list) for u, v, w in times: graph[u].append((v, w)) pq = [(0, K)] dist = {} while pq: d, node = heapq.heappop(pq) if node in dist: continue dist[node] = d for nei, d2 in graph[node]: if nei not in dist: heapq.heappush(pq, (d+d2, nei)) return max(dist.values()) if len(dist) == N else -1
def kClosest(self, points: List[List[int]], K: int) -> List[List[int]]: # 방법1: list sort dist = [int(i[0])**2 + int(i[1])**2 for i in points] idxs = sorted(range(len(dist)), key=lambda k: dist[k])[:K] return np.array(points)[idxs] # 방법2: priority queue heap = [] for x, y in points: dist = x**2 + y**2 heapq.heappush(heap, (dist, x, y)) # (우선순위, 값) result = [] for _ in range(K): (dist, x, y) = heapq.heappop(heap) result.append((x, y)) return result
def mergeKLists(self, lists: List[ListNode]) -> ListNode: head = ListNode(0) current = head heap = [] for i, li in enumerate(lists): if li: heapq.heappush(heap, (li.val, i, li)) while heap: val, idx, node = heapq.heappop(heap) current.next = node current = current.next node = node.next if node is None: continue heapq.heappush(heap, (node.val, idx, node)) return head.next
def findShortestWay(self, maze, ball, hole): m, n, q, stopped = len(maze), len(maze[0]), [(0, "", ball[0], ball[1])], {(ball[0], ball[1]): [0, ""]} while q: dist, pattern, x, y = heapq.heappop(q) if [x, y] == hole: return pattern for i, j, p in ((-1, 0, "u"), (1, 0, "d"), (0, -1, "l"), (0, 1, "r")): newX, newY, d = x, y, 0 while 0 <= newX + i < m and 0 <= newY + j < n and maze[newX + i][newY + j] != 1: newX += i newY += j d += 1 if [newX, newY] == hole: break if (newX, newY) not in stopped or [dist + d, pattern + p] < stopped[(newX, newY)]: stopped[(newX, newY)] = [dist + d, pattern + p] heapq.heappush(q, (dist + d, pattern + p, newX, newY)) return "impossible"
def networkDelayTime(self, times, N, K): pq = [] adj = [[] for _ in range(N+1)] for time in times: adj[time[0]].append((time[1], time[2])) fin, res = set(), 0 heapq.heappush(pq, (0, K)) while len(pq) and len(fin) != N: cur = heapq.heappop(pq) fin.add(cur[1]) res = cur[0] for child, t in adj[cur[1]]: if child in fin: continue heapq.heappush(pq, (t+cur[0], child)) return res if len(fin) == N else -1
def shortestDistance(self, maze, start, destination): """ :type maze: List[List[int]] :type start: List[int] :type destination: List[int] :rtype: int """ # DFS 不撞南墙不回头,回头看看路近否 self.m = len(maze) self.n = len(maze[0]) distance = [[float('inf')] * self.n for _ in range(self.m)] queue = [] heapq.heappush(queue, (0, start[0], start[1])) dir = ((0, 1), (0, -1), (1, 0), (-1, 0)) while queue: curr, x, y = heapq.heappop(queue) if x == destination[0] and y == destination[1]: return curr else: for dx, dy in dir: xn, yn = x + dx, y + dy temp = curr while 0 <= xn < self.m and 0 <= yn < self.n and maze[xn][ yn] != 1: xn += dx yn += dy temp += 1 xn -= dx yn -= dy if distance[xn][yn] > temp: distance[xn][yn] = temp heapq.heappush(queue, (temp, xn, yn)) return -1
def kWeakestRows(self, mat: List[List[int]], k: int) -> List[int]: count = {} heap = [] result = [] for i in range(len(mat)): for j in range(len(mat[0])): if mat[i][j] == 1: if i in count: count[i] += 1 else: count[i] = 1 else: if i not in count: count[i] = 0 for key, value in count.items(): heapq.heappush(heap, (value, key)) for i in range(k): result.append(heapq.heappop(heap)[1]) return result
def minCost2(self, grid: List[List[int]]) -> int: RIGHT, LEFT, DOWN, UP = range(1, 5) R, C = len(grid), len(grid[0]) dic = {(0, 0): 0} hp = [(0, 0, 0)] while hp: cost, r, c = heapq.heappop(hp) r, c = abs(r), abs(c) if r == R-1 and c == C-1: return cost for nr, nc, direc in ((r-1, c, UP), (r, c+1, RIGHT), (r+1, c, DOWN), (r, c-1, LEFT)): if nr < 0 or nr >= R or nc < 0 or nc >= C: continue # coords out of bound new_cost = cost+1 if direc != grid[r][c] else cost # cost increase if direction differs if (nr, nc) in dic and dic[(nr,nc)] <= new_cost: continue # we have visited this cell with smaller cost dic[(nr, nc)] = new_cost heapq.heappush(hp, (new_cost, -nr, -nc))
def findCheapestPrice(self, n, flights, src, dst, K): remain, ret, stop = [], float('inf'), 0 weights = [sys.maxint for i in range(n)] graph = [{} for i in range(n)] for s,d,w in flights: graph[s][d]=w heapq.heappush(remain, (0, src)) weights[src] = 0 while remain and stop <= K: tmp, remain = remain, [] while tmp: weight, node = heapq.heappop(tmp) for tonode, toweight in graph[node].items(): if weights[tonode] > weight + toweight: weights[tonode] = weight + toweight heapq.heappush(remain, (weights[tonode], tonode)) # this two lines are important if tonode == dst and weights[tonode]<ret: ret = weights[tonode] stop+=1 return ret if ret < float('inf') else -1
def slidingPuzzle(self, board): self.scores = [0] * 6 goal_pos = {1:(0, 0), 2:(0, 1), 3: (0, 2), 4: (1,0), 5:(1,1), 0:(1, 2)} for num in range(6): # Pre calculate manhattan distances self.scores[num] = [[abs(goal_pos[num][0] - i) + abs(goal_pos[num][1] - j) for j in range(3)] for i in range(2)] Node = namedtuple('Node', ['heuristic_score', 'distance', 'board']) heap = [Node(0, 0, board)] closed = [] while len(heap) > 0: node = heapq.heappop(heap) if self.get_score(node.board) == 0: return node.distance elif node.board in closed: continue else: for neighbor in self.get_neighbors(node.board): if neighbor in closed: continue heapq.heappush(heap, Node(node.distance + 1 + self.get_score(neighbor), node.distance + 1, neighbor)) closed.append(node.board) return -1
def findCheapestPrice(self, n, flights, src, dst, K): graph = collections.defaultdict(dict) for u, v, w in flights: graph[u][v] = w best = {} pq = [(0, 0, src)] while pq: cost, k, place = heapq.heappop(pq) if k > K+1 or cost > best.get((k, place), float('inf')): continue if place == dst: return cost for nei, wt in graph[place].iteritems(): newcost = cost + wt if newcost < best.get((k+1, nei), float('inf')): heapq.heappush(pq, (newcost, k+1, nei)) best[k+1, nei] = newcost return -1 # Complexity Analysis # Time Complexity: O(E + n \log n)O(E+nlogn), where EE is the total number of flights. # Space Complexity: O(n)O(n), the size of the heap.
def mostCommonWord(self, paragraph: str, banned: List[str]) -> str: paragraph = paragraph.lower() words = re.sub(r'[^\w]', ' ', paragraph).split(" ") heap = [] word_count = {} for word in words: if word != "": if word in word_count: word_count[word] += 1 else: word_count[word] = 1 for key,value in word_count.items(): heapq.heappush(heap,(-value,key)) while heap: top = heapq.heappop(heap) if top[1] not in banned: return top[1] continue
def sortArray(self, nums): sorted_list=[] heapq.heapify(nums) return [(heapq.heappop(nums)) for i in range(len(nums))]
'''
Graph & Topological Sort & Trie & BIT(Indexed) & Segment Tree & BST(Search): 完成到332 Recursion & DP : 完成到392 Sort & Searching : 完成到392 # Data Structure: from collections import deque lst = deque(lst) left_most = lst.popleft() right_most = lst.pop() from collections import heapq heap = [] heapq.heappush(heap, (key, stuff)) # Push the (key, stuff) pair sorted by key heapq.heappop(heap) # return the (key, stuff) pair with smallest # Index lst.index(val) -> index of val in the lst # Random random.randint(a, b) -> A random int value from a to b (Both inclusive) # Linked List # Definition for singly-linked list. class ListNode(object): def __init__(self, x): self.val = x self.next = None
class Solution: # maintain the heap # T: O(clogN), N as number of employees, C the number of all intervals/jobs # O(logN) for push and pop in heap of size N # O(c) as number of such operations def employeeFreeTime3(self, schedule: '[[Interval]]') -> '[Interval]': ans = [] # (job_idx_th start time, user ID, job idx) pq = [(emp[0].start, empID, 0) for empID, emp in enumerate(schedule)] heapq.heapify(pq) # anchor: minimal start time for all employee prev_end = pq[0][0] # start time! while pq: # e_id: employee id; cur_jobId: current job ID start_time, e_id, cur_jobId = heapq.heappop(pq) # no overlap if start_time > prev_end: ans.append(Interval(prev_end, start_time)) # overlap, update prev_end prev_end = max(prev_end, schedule[e_id][cur_jobId].end) # # if there are more intervals available for the same employee, add their next interval if cur_jobId + 1 < len(schedule[e_id]): # push next job into it heapq.heappush(pq, (schedule[e_id][cur_jobId+1].start, e_id, cur_jobId+1)) return ans # minheap, still not optimal since all intervals in heap # T: O(clogc), N as number of employees, C the number of all intervals # S: O(N) def employeeFreeTime2(self, schedule: '[[Interval]]') -> '[Interval]': res = [] intervals = [(i.start, i.end) for emp in schedule for i in emp] heapify(intervals) start, end = heappop(intervals) prev_end = end while intervals: cur_start, cur_end = heappop(intervals) if cur_start > prev_end: res.append(Interval(prev_end, cur_start)) prev_end = cur_end else: prev_end = max(cur_end, prev_end) return res # T: O(clogc), n as number of all intervals, not optimal def employeeFreeTime1(self, schedule: '[[Interval]]') -> '[Interval]': intervals = sorted([i for emp in schedule for i in emp], \ key=lambda x: x.start) res, pre = [], intervals[0] for cur_interval in intervals[1:]: # overlap, extend/update the prev_end if cur_interval.start <= pre.end and cur_interval.end > pre.end: pre.end = cur_interval.end # no overlap elif cur_interval.start > pre.end: res.append(Interval(pre.end, cur_interval.start)) pre = cur_interval return res