def leastInterval(self, tasks, n): """ Solution: Calculating Idle Slot Time Complexity: O(n) Space Complexity: O(n) Inspired By: MySELF!! (684ms, beat 20.24%) :type tasks: List[str] :type n: int :rtype: int """ freq2task_map = collections.Counter(tasks) max_freq = max(freq2task_map.values()) base_sec = [] for k, v in freq2task_map.iteritems(): if v == max_freq: base_sec.append(k) for key in base_sec: freq2task_map.pop(key) res = len(base_sec) _heap = [] for i in range(max_freq-1): pq.heappush(_heap, (len(base_sec), base_sec[:])) freq2task_map = [(k, v) for k, v in freq2task_map.iteritems()] while freq2task_map: k, v = freq2task_map.pop() for i in range(v): sec_len, sec = pq.heappop(_heap) sec.append(k) pq.heappush(_heap, (1 + sec_len, sec)) while _heap: sec_len, sec = _heap.pop() res += max(n+1, sec_len) return res
def mincostToHireWorkers(self, quality, wage, K): """ Solution: Heap Time Complexity: O(nlog(n)) Space Complexity: O(n) Perf: Runtime: 424 ms, faster than 31.63% / Memory Usage: 14.1 MB, less than 12.00% Inspired By: - https://leetcode.com/problems/minimum-cost-to-hire-k-workers/discuss/237268/Python-heap-solution-with-clean-code-and-explanation - https://leetcode.com/problems/minimum-cost-to-hire-k-workers/solution/ TP: - Using wage[i]/quality[i] as sorting points :type quality: List[int] :type wage: List[int] :type K: int :rtype: float """ m = len(quality) wkr_ratio = [] for i in range(m): wkr_ratio.append((float(wage[i]) / quality[i], quality[i])) wkr_ratio.sort() h = [] min_cost = float('inf') total_qua = 0 for ratio, qua in wkr_ratio: total_qua += qua pq.heappush(h, -qua) if len(h) == K: min_cost = min(min_cost, total_qua * ratio) elif len(h) > K: total_qua += pq.heappop(h) min_cost = min(min_cost, total_qua * ratio) return min_cost
def findCheapestPrice(self, n, flights, src, dst, K): """ Solution: BFS + Dijsktra Time Complexity: Space Complexity: O(n) (n: heap length) Inspired By: - https://leetcode.com/problems/cheapest-flights-within-k-stops/solution/ - https://leetcode.com/problems/cheapest-flights-within-k-stops/discuss/115541/JavaPython-Priority-Queue-Solution TP: - Using Dijkstra Algorithm but at same time keep the stops under K :type n: int :type flights: List[List[int]] :type src: int :type dst: int :type K: int :rtype: int """ graph = collections.defaultdict(dict) for u, v, w in flights: graph[u][v] = w best = dict() pq = [(0, 0, src)] while pq: curr_cost, curr_stop, curr_city = pq.heappop(pq) if curr_stop > K+1 or curr_cost > best.get((curr_stop, curr_city), float('inf')): continue if curr_city == dst: return curr_cost for next_stop, cost in graph[curr_city].iteritems(): new_cost = cost + curr_cost if new_cost < best.get((curr_stop+1, dst), float('inf')): best[(curr_stop+1, next_stop)] = new_cost pq.heappush(pq, (new_cost, curr_stop + 1, next_stop)) return -1
def minPathSum(self, grid): """ Solution: Dijkestra Time Complexity: Space Complexity: O(m*n) Inspired By: MySELF!! TP: - In this question we are not allowed to go up or left :type grid: List[List[int]] :rtype: int """ pq = [] pq.heappush(pq, (grid[0][0], (0, 0))) visited = set() m = len(grid) n = len(grid[0]) #directions = [(-1, 0),(0, -1), (1, 0), (0, 1)] directions = [(1, 0), (0, 1)] while pq: cost, cord = pq.heappop(pq) i, j = cord if not (i, j) in visited: visited.add(cord) if (i, j) == (m - 1, n - 1): return cost else: for x_dir, y_dir in directions: x = x_dir + cord[0] y = y_dir + cord[1] if 0 <= x < m and 0 <= y < n: pq.heappush(pq, (cost + grid[x][y], (x, y)))
def trapRainWater(self, heightMap): """ Solution: Heap (Priority Q) Time Complexity: O(m*n) Space Complexity: O(m*n) Inspired By: - https://leetcode.com/problems/trapping-rain-water-ii/discuss/89466/python-solution-with-heap - https://www.youtube.com/watch?time_continue=7&v=cJayBq38VYw TP: - first we have to define "how to trap a water" - since all border can't "trap" any water, we can put all border elements into the heapQ - The we go through the following procedure: - pop from heapQ (the pop will give us lowest height cell) - visit all its 'unvisited neighbor' - if neighbor's height is smaller than 'pop' height, means we can trap water, so add the height diff to res - then we push this neighbor into heap - !!! Tricky: we need to update this neighbor's height with max(height_of_neighbor, height_pop) - WHY ?? --> if neighbor's height is smaller, then we already add the 'trap' water during this iteration thus next time when its 'neighbor' turn from heapQ we can have correct amount of water - consider this: 5 7 3 <-- current pop is 7 4 6 1 <-- visit neighbor 6, collect water 7-6 = 1, push 6 with height of 7 into heap 6 5 7 <-- next time when pop 6 and visit neighbor 5, neighbor should able to trap water 7 - 5 = 2 7 7 8 - Since we start from lowest point from all borders, we can guarantee for following procedure the water will be trapped correctly :type heightMap: List[List[int]] :rtype: int """ if not heightMap or not heightMap[0]: return 0 import pq m = len(heightMap) n = len(heightMap[0]) visited = [[False for _ in range(n)] for _ in range(m)] res = 0 heap = [] for i in range(m): for j in range(n): if i == 0 or i == m-1 or j == 0 or j == n-1: pq.heappush(heap, (heightMap[i][j], i, j)) visited[i][j] = True while heap: height, i, j = pq.heappop(heap) for x, y in [(i-1, j), (i+1, j), (i, j-1), (i, j+1)]: if 0 <= x < m and 0 <= y < n and not visited[x][y]: res += max(0, height - heightMap[x][y]) pq.heappush(heap, (max(heightMap[x][y], height), x, y)) visited[x][y] = True return res
def findMinCost(self, numTotalAvailableCities, numTotalAvailableRoads, roadsAvailable, numNewRoadsConstruct, costNewRoadsConstruct): UF = UnionFind(numTotalAvailableCities, roadsAvailable) candidate_road = [] for city1, city2, cost in costNewRoadsConstruct: pq.heappush(candidate_road, (cost, city1, city2)) res = 0 while numTotalAvailableRoads < numTotalAvailableCities-1: cost, city1, city2 = pq.heappop(candidate_road) r1 = UF.find(city1) r2 = UF.find(city2) if r1 != r2: UF.union(city1, city2) numTotalAvailableRoads += 1 res += cost return res
def mergeKSortedLists(self, lists): """ Time: O(nlog(k)) Space: O(n) :param lists: :return: """ pq = [] res = [] for idx, list in enumerate(lists): pq.heappush(pq, (list.pop(0), idx)) while pq: val, idx = pq.heappop(pq) res.append(val) if lists[idx]: pq.heappush(pq, (lists[idx].pop(0), idx)) return res
def minMeetingRooms(self, intervals): """ Solution: Heapq + Sorting Time Complexity: O(nlog(n)) Space Complexity: O(n) Perf: Runtime: 80 ms, faster than 22.20% / Memory Usage: 17.9 MB, less than 5.35% Inspired By: https://leetcode.com/problems/meeting-rooms-ii/solution/ :type intervals: List[Interval] :rtype: int """ intervals.sort(key=lambda x: x.start) schedule = [] for interval in intervals: if not schedule: schedule.append(interval.end) else: if interval.start >= schedule[0]: pq.heappushpop(schedule, interval.end) else: pq.heappush(schedule, interval.end) return len(schedule)
def mergeKLists(self, lists): """ Time: O(nlog(k)) n: number of nodes, k: len of lists Perf: Runtime: 108 ms, faster than 57.15% / Memory Usage: 17.6 MB, less than 38.93% :type lists: List[ListNode] :rtype: ListNode """ if not lists: return None stack = [] head = ListNode(None) start = head for node in lists: if node: pq.heappush(stack, (node.val, node)) while stack: val, curNode = pq.heappop(stack) head.next = curNode if curNode.next: pq.heappush(stack, (curNode.next.val, curNode.next)) head = head.next return start.next
def nthUglyNumber(self, n): """ Facebook T:O(nlogn) S:O(n) Solution: heapq (priority queue) Time Complexity: O(3*n) Space Complexity: O(3*n) Perf: Runtime: 896 ms, faster than 8.14% / Memory Usage: 10.9 MB, less than 35.21% Inspired By: MySELF!! :type n: int :rtype: int """ cand = [1] for i in range(n - 1): k = pq.heappop(cand) if k * 2 not in cand: pq.heappush(cand, k * 2) if k * 3 not in cand: pq.heappush(cand, k * 3) if k * 5 not in cand: pq.heappush(cand, k * 5) return pq.heappop(cand)
def sortNArray(self, nums1, nums2, nums3): """ Time Complexity: O(nlog(k)) Space Complexity: O(k) :param nums1: :param nums2: :param nums3: :return: """ pq = [] res = [] if nums1: pq.heappush(pq, (nums1.pop(0), 1)) if nums2: pq.heappush(pq, (nums2.pop(0), 2)) if nums3: pq.heappush(pq, (nums3.pop(0), 3)) while pq: num, arrayIdx = pq.heappop(pq) if num not in res: res.append(num) if arrayIdx == 1: if nums1: pq.heappush(pq, (nums1.pop(0), 1)) elif arrayIdx == 2: if nums2: pq.heappush(pq, (nums2.pop(0), 2)) else: if nums3: pq.heappush(pq, (nums3.pop(0), 3)) return res