heap is a specialized tree-based data structure which is essentially an almost complete tree. In a min heap, the parent nodes
always smaller than childern nodes.
1405. Longest Happy String
class Solution:
def longestDiverseString(self, a: int, b: int, c: int) -> str:
hp = []
if a != 0:
heappush(hp, (-a, 'a'))
if b != 0:
heappush(hp, (-b, 'b'))
if c != 0:
heappush(hp, (-c, 'c'))
re = ''
while hp:
count1, c1 = heapq.heappop(hp)
if len(re) >= 2 and c1 == re[-1] and c1 == re[-2]:
if hp:
count2, c2 = heapq.heappop(hp)
re += c2
count2 += 1
if count2 <= -1:
heapq.heappush(hp, (count2, c2))
heapq.heappush(hp, (count1, c1))
else:
return re
else:
re += c1
count1 += 1
if count1 <= -1:
heapq.heappush(hp, (count1, c1))
return re
1094. Car Pooling
class Solution:
def carPooling(self, trips: List[List[int]], capacity: int) -> bool:
trip = [[b, c, a] for a, b, c in trips]
trip.sort()
h = []
while trip:
start, end, num = trip.pop(0)
# print("cur", start, end, num, "heap", h)
if not h:
heapq.heappush(h, [end, num])
capacity -= num
else:
while h:
e, n = h[0]
# print("top heap", e, n, capacity)
if start >= e:
heapq.heappop(h) # needs to keep pop till not meet start>= e and then push cur into heap
# print("pop", e, n)
capacity += n
else:
break
heapq.heappush(h, [end, num])
capacity -= num
# print("capacity", capacity)
if capacity < 0:
return False
return True
def carPooling(self, trips: List[List[int]], capacity: int) -> bool:
lst = []
for n, start, end in trips:
lst.append((start, n))
lst.append((end, -n))
lst.sort()
pas = 0
for loc in lst:
pas += loc[1]
if pas > capacity:
return False
return True
1882. Process Tasks Using Servers
class Solution:
def assignTasks(self, servers: List[int], tasks: List[int]) -> List[int]:
avaSrv = [(weight, i) for i, weight in enumerate(servers)] # heap 1: (weight, Server index) # O(n)
heapq.heapify(avaSrv)
onTasks = [] # heap 2 ongoing tasks: (endTime, serverIndex)
re = []
curTime = 0
for t, needTime in enumerate(tasks): # O(m)
curTime = max(t, curTime)
if not avaSrv:
curTime = onTasks[0][0]
while onTasks and onTasks[0][0] <= curTime:
_, serIdx = heapq.heappop(onTasks)
heapq.heappush(avaSrv, (servers[serIdx], serIdx)) # log(n)
_, idx = heapq.heappop(avaSrv)
heapq.heappush(onTasks, (curTime + needTime, idx)) # log(m)
re.append(idx)
return re
# heapify takes O(n) time. The loop iterates m times and both heaps have sizes no more than n. Thus, the overall run-time is O(n + mlogn).
1387. Sort Integers by The Power Value
class Solution:
def getKth(self, lo: int, hi: int, k: int) -> int:
self.d = {}
def power(x):
if x == 1:
return 1
if x in self.d:
return self.d[x]
self.d[x] = (power(x / 2) if x % 2 == 0 else power(3 * x + 1)) + 1
return self.d[x]
re = [(power(x), x) for x in range(lo, hi+1)]
heapq.heapify(re)
for i in range(k):
res = heapq.heappop(re)
return res[1]
1642. Furthest Building You Can Reach
class Solution:
def furthestBuilding(self, heights: List[int], bricks: int, ladders: int) -> int:
heap = []
for i in range(len(heights) - 1):
d = heights[i+1] - heights[i]
if d > 0:
heapq.heappush(heap, d)
if len(heap) > ladders: # means we have to use bricks, we will choose the min diff d to use
bricks -= heapq.heappop(heap)
if bricks < 0:
return i
return len(heights) - 1
1942. The Number of the Smallest Unoccupied Chair
class Solution:
def smallestChair(self, times: List[List[int]], targetFriend: int) -> int:
'''
when people left, return the chair to ava_seat[]
when people arr, check if there is any returned chair, if so, take the smallest one
if not, the seat index he will take will be the current total people - 1 in the people
'''
total_people = 0
arr_heap, lev_heap, ava_seat = [], [], []
d = {} # map people index to seat index
for i, (arr, lev) in enumerate(times):
heapq.heappush(arr_heap, [arr, i])
heapq.heappush(lev_heap, [lev, i])
while arr_heap:
arr, cur_i = heapq.heappop(arr_heap) # arr_time or cur time, cur people index
total_people += 1
while lev_heap[0][0] <= arr: # people left before cur time
lev, i = heapq.heappop(lev_heap)
heapq.heappush(ava_seat, d[i]) # return the seat to the ava_seat
total_people -= 1
else:
# check if there is an return seat, if so, take it
if ava_seat:
take_seat_i = heapq.heappop(ava_seat)
d[cur_i] = take_seat_i
else:
# seat_i will be the total people - 1
d[cur_i] = total_people - 1
if cur_i == targetFriend:
return d[cur_i]
1488. Avoid Flood in The City
class Solution:
def avoidFlood(self, rains: List[int]) -> List[int]:
# heap
lake_rain_days = collections.defaultdict(list)
N = len(rains)
re = [-1] * N
heap = [] # stores the lakes need to be emptyed
full = set()
for day, lake in enumerate(rains):
lake_rain_days[lake].append(day)
for i, lake in enumerate(rains):
if lake:
if lake in full:
return []
full.add(lake)
lake_rain_days[lake].pop(0) # 当前的天
if lake_rain_days[lake]:
heapq.heappush(heap, lake_rain_days[lake][0]) # 里面存的是day 不是lake
else:
if heap:
re[i] = rains[heapq.heappop(heap)] # 里面存的是 day
full.remove(re[i])
else:
re[i] = 1 ## 多个0 前面没有lake可以empty
return re
1834. Single-Threaded CPU
class Solution:
def getOrder(self, tasks: List[List[int]]) -> List[int]:
tasks = sorted([task[0], task[1], i] for i, task in enumerate(tasks)) # sort the task by start time
res = []
h = []
cur_time = tasks[0][0] # set the current time to the first start time in the task list.
i = 0
n = len(tasks)
while len(res) < n: # end when the res has the same # of tasks with tasks
# Push all tasks whose start time is ≤ the current time into heap h
while i < n and tasks[i][0] <= cur_time:
heapq.heappush(h, (tasks[i][1], tasks[i][2])) # process time, index
i += 1
if h: # all the tasks in h has start_time <= cur_time
pro_time, index = heapq.heappop(h)
cur_time += pro_time
res.append(index)
elif i < n:
cur_time = tasks[i][0]
return res
215. Kth Largest Element in an Array
373. Find K Pairs with Smallest Sums
class Solution(object):
def kSmallestPairs(self, nums1, nums2, k):
"""
:type nums1: List[int]
:type nums2: List[int]
:type k: int
:rtype: List[List[int]]
"""
heap = []
res = []
if not nums1 or not nums2:
return res
# add init pairs (sum, nums1[i], nums2[0], ids of nums2)
for i in xrange(min(k, len(nums1))):
heapq.heappush(heap, [nums1[i]+nums2[0], nums1[i], nums2[0], 0]) # 0 is the index of nums2
for i in xrange(min(k, len(nums1)*len(nums2))):
cur = heapq.heappop(heap)
res.append([cur[1], cur[2]])
if cur[3] < len(nums2)-1: # cur[3] is the idx of nums3: still at least one elem after num2 in array nums2
idx = cur[3] + 1
heapq.heappush(heap, [cur[1]+nums2[idx], cur[1], nums2[idx], idx])
return res
378. Kth Smallest Element in a Sorted Matrix
我第一个想法是Heap,最小堆解,但是不会写,因为heap用得太少了,库都不熟悉。
此题还有binary search的解法,速度更快,时间复杂度更低。
heap: 堆排序时间复杂度是nlogn,插入是logn
- insert an element into heap: O(log(n)), where n is the width of the matrix
- find k the k-th element O(k)
- Overall: O(klog(n))
class Solution(object):
def kthSmallest(self, matrix, k):
"""
:type matrix: List[List[int]]
:type k: int
:rtype: int
"""
h = [(row[0], row, 1) for row in matrix]
heapq.heapify(h)
for i in xrange(k-1):
num, row, index = h[0]
if index < len(matrix[0]):
heapq.heapreplace(h, (row[index], row, index+1))
else:
heapq.heappop(h)
return h[0][0]
binary search:
- Since we are given 1 <= k <= n^2, the kth number must exist in [lo, hi] range.
- We use binary search to find the minimum number
A
, such that the count of ( numbers satisfyingnum <= A
) is >= k. - The time complexity is O(n * log(n) * log(N)), where N is the search space that ranges from the smallest element to the biggest element. You can argue that int implies N = 2^32, so log(N) is constant. In a way, this is an O(n * log(n)) solution.
好好好,good good good ,this is the first time that I know we can use binary search on such a nxm matrix.
class Solution(object):
def kthSmallest(self, matrix, k):
"""
:type matrix: List[List[int]]
:type k: int
:rtype: int
"""
low, high = matrix[0][0], matrix[-1][-1]
while low < high:
mid = (low + high) / 2
count, j = 0, len(matrix[0]) - 1
for i in xrange(len(matrix)):
while j >= 0 and matrix[i][j] > mid:
j -= 1
count += j + 1
if count < k: low = mid + 1
else: high = mid
return low
295. Find Median from Data Stream
class MedianFinder(object):
def __init__(self):
"""
initialize your data structure here.
"""
self.heaps = [], []
def addNum(self, num):
"""
:type num: int
:rtype: void
"""
small, large = self.heaps
heapq.heappush(small, -heapq.heappushpop(large, num))
if len(large) < len(small):
heapq.heappush(large, -heapq.heappop(small))
def findMedian(self):
"""
:rtype: float
"""
small, large = self.heaps
if len(small) == len(large):
return (large[0]-small[0]) / 2.0
else:
return large[0]
703. Kth Largest Element in a Stream
class KthLargest(object):
def __init__(self, k, nums):
"""
:type k: int
:type nums: List[int]
"""
heapq.heapify(nums) # inplace
self.heap = nums
self.k = k
while len(self.heap) > k:
heapq.heappop(self.heap)
def add(self, val):
"""
:type val: int
:rtype: int
"""
if len(self.heap) < self.k:
heapq.heappush(self.heap, val)
return self.heap[0]
if val > self.heap[0]:
heapq.heappushpop(self.heap, val)
return self.heap[0]