Skip to content

Commit

Permalink
new question
Browse files Browse the repository at this point in the history
  • Loading branch information
Samir Paul committed Jun 12, 2022
1 parent 86c50be commit 4cae70d
Show file tree
Hide file tree
Showing 21 changed files with 753 additions and 3 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# https://leetcode.com/problems/minimum-path-cost-in-a-grid/

class Solution:
def minPathCost(self, grid: List[List[int]], moveCost: List[List[int]]) -> int:
row = len(grid)
col = len(grid[0])
dp = [[0]*col for i in range(row)]

for j in range(col):
dp[0][j] = grid[0][j]

for i in range(1, row):
for j in range(col):
cost = [0]*col
for k in range(col):
cost[k] = grid[i][j] + moveCost[grid[i-1][k]][j] + dp[i-1][k]
dp[i][j] = min(cost)

return min(dp[-1])


# Time: O(row * col * col)
# Space: O(row * col)

43 changes: 43 additions & 0 deletions 06_Binary-Trees/Count Complete Tree Nodes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# https://leetcode.com/problems/count-complete-tree-nodes/
# https://youtu.be/u-yWemKGWO0

'''
Only traversing along the left and right boundary.
If both left and right height are equal then
the bottom level would be full from left to right and total no. of nodes in that subtree
is 2^h - 1.
If left and right height are not equal then add +1 for current root and go to left child
and right child.
'''
class Solution:
def countNodes(self, root: Optional[TreeNode]) -> int:
if not root: return 0

leftHeight = self.getLeftHeight(root)
rightHeight = self.getRightHeight(root)

if leftHeight == rightHeight:
return 2 ** leftHeight - 1
else:
return 1 + self.countNodes(root.left) + self.countNodes(root.right)


def getLeftHeight(self, node):
height = 0
while node:
height += 1
node = node.left
return height

def getRightHeight(self, node):
height = 0
while node:
height += 1
node = node.right
return height

# Height = H = log(n) where n = total number of nodes
# Time: O(H * H) = O(log(n)^2) = O(Log^2 n)
# Auxiliary Space: O(H) = O(log(n))

30 changes: 30 additions & 0 deletions 06_Binary-Trees/Number of Good Leaf Nodes Pairs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# https://leetcode.com/problems/number-of-good-leaf-nodes-pairs/

'''
Traverse from bottom to top (Postorder Traversal) and keep track of the distance of the
leaf nodes to each node. Once those leaf nodes meet a Lowest Common Ancestor,
we can immediately check whether they are good pairs.
'''

class Solution:
def countPairs(self, root: TreeNode, distance: int) -> int:
count = 0

def dfs(node):
nonlocal count

if not node: return []
if not node.left and not node.right: return [1]

left = dfs(node.left)
right = dfs(node.right)

count += sum(l + r <= distance for l in left for r in right)
return [n + 1 for n in left + right if n + 1 < distance]

dfs(root)
return count

# Time: O(N)
# Space: O(N)

Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# https://leetcode.com/problems/path-with-minimum-effort/

# https://youtu.be/FabSLaGu0NI

# Method 1 --------> using Dijkstra's Algorithm
class Solution:
def minimumEffortPath(self, heights: List[List[int]]) -> int:
row = len(heights)
col = len(heights[0])

minHeap = []
heapq.heappush(minHeap, (0, 0, 0)) # (distance, row, col)

directions = [(-1, 0), (1, 0), (0, -1), (0, 1)]
visited = set()
dp = [[2**31]*col for i in range(row)]

while minHeap:
d, r, c = heapq.heappop(minHeap)
if (r, c) in visited: continue
visited.add((r,c))
dp[r][c] = d
if r == row-1 and c == col-1: return dp[r][c]
for direc in directions:
nr = r + direc[0]
nc = c + direc[1]
if 0 <= nr < row and 0 <= nc < col:
nd = max(dp[r][c], abs(heights[r][c] - heights[nr][nc]))
if nd < dp[nr][nc]:
heapq.heappush(minHeap, (nd, nr, nc))

return 0

# Time: O(r*c * log(r*c))
# Space: O(r * c)


'''
# Method 2 --------> using Binary Search
class Solution:
def minimumEffortPath(self, heights: List[List[int]]) -> int:
'''
63 changes: 63 additions & 0 deletions 08_Heap/03. Kth Largest Element in a Stream.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# https://leetcode.com/problems/kth-largest-element-in-a-stream/

'''
By default Min Heap is implemented by heapq library.
In a Min-Heap the minimum element present at the root. In pop operation root node is removed.
'''

class KthLargest:

def __init__(self, k: int, nums: List[int]):
self.k = k
self.minHeap = [] # Min Heap
for num in nums:
heapq.heappush(self.minHeap, num) # adding all elements to min heap

while len(self.minHeap) > k:
heapq.heappop(self.minHeap) # Only keeping k maximum elements


def add(self, val: int) -> int:
heapq.heappush(self.minHeap, val) # first add to min heap

if len(self.minHeap) > self.k: # if length greater pop minimum element as root is the min
heapq.heappop(self.minHeap)

return self.minHeap[0] # root is minHeap[0] as root is k'th max

# Time: O(N log(N)) # as heap size is N so heappush takes log(N) time
# Space: O(N)



# Method-2 Using the given add function to add only k elements so that we can save space
import heapq
class KthLargest:
"""
The idea is to ALWAYS maintain a MIN heap with only K elements
- in this case, the K-the largest element (in the stream)
- will always be at the root position
"""
def __init__(self, k: int, nums: List[int]):
self.heap = []
self.k = k

for num in nums:
self.add(num) # add elements using the function below

def add(self, val: int) -> int:

heapq.heappush(self.heap, val)

# if after adding the new item causes
# the heap size to increase beyond k,
# then pop out the smallest element
if len(self.heap) > self.k:
heapq.heappop(self.heap)

return self.heap[0] # the root element

# Time: O(N log(K)) # as heap size if k so heappush takes log(k) time
# Space: O(K) # as only making heap of size k

40 changes: 40 additions & 0 deletions 08_Heap/04. Find Median from Data Stream.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# https://leetcode.com/problems/find-median-from-data-stream/
# https://youtu.be/itmhHWaHupI

# we can easyly solve using arr operations in O(N) time but to solve in log(N) time we have to use heap
# using 2 heaps one is left side of median ig. self.small(maxheap) and another is right side of median self.large(minheap)

import heapq
class MedianFinder:

def __init__(self):
self.small = [] # Max Heap
self.large = [] # Min Heap

def addNum(self, num: int) -> None:
heapq.heappush(self.small, -num) # always pushing on small (maxheap) then comparing

if self.small and self.large and -self.small[0] > self.large[0]: # if newly added element greater
val = -heapq.heappop(self.small)
heapq.heappush(self.large, val)

if len(self.small) > len(self.large) + 1:
val = -heapq.heappop(self.small)
heapq.heappush(self.large, val)

if len(self.large) > len(self.small) + 1:
val = heapq.heappop(self.large)
heapq.heappush(self.small, -val)


def findMedian(self) -> float:
if len(self.small) > len(self.large):
return -self.small[0]

if len(self.large) > len(self.small):
return self.large[0]

return (-self.small[0] + self.large[0]) / 2

# Time: O(log(N))
# Space: O(N)
41 changes: 41 additions & 0 deletions 08_Heap/05. Kth Largest Element in an Array.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# https://leetcode.com/problems/kth-largest-element-in-an-array/

#------ Method 1 ---------- Using Min Heap Time: O(n log(k))
import heapq
class Solution:
def findKthLargest(self, nums, k):
self.minHeap = [] # as root of min heap is minimum and root is removed in pop operation
self.heapLength = 0 # for calculating length of heap in constant time else len() would take O(k) time

def addToHeap(num):
heapq.heappush(self.minHeap, num)
self.heapLength += 1
if self.heapLength > k: # always trying to maintain heap length k
heapq.heappop(self.minHeap)
self.heapLength -= 1

for num in nums:
addToHeap(num)

return self.minHeap[0]

# Time: O(N log(k)) ; O(N) for traversal and log(k) for pushing num to a heap of size k
# Space: O(k) ; as the minHeap is always of size k


#------ Method 2 ---------- Using QUick Quick-Select (idea Quick Sort)
class Solution:
def findKthLargest(self, nums, k):
pivot = nums[0]

left = [num for num in nums if num < pivot]
equal = [num for num in nums if num == pivot]
right = [num for num in nums if num > pivot]

if k <= len(right): return self.findKthLargest(right, k)
elif len(right) < k <= len(right) + len(equal): return equal[0]
else: return self.findKthLargest(left, k - len(right) - len(equal))

# Average Time Complexity: O(N)
# Worst Case Time Complexity: O(N^2)
# Space Complexity: O(N)
44 changes: 44 additions & 0 deletions 08_Heap/06. Path With Minimum Effort.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# https://leetcode.com/problems/path-with-minimum-effort/

# https://youtu.be/FabSLaGu0NI

# Method 1 --------> using Dijkstra's Algorithm
class Solution:
def minimumEffortPath(self, heights: List[List[int]]) -> int:
row = len(heights)
col = len(heights[0])

minHeap = []
heapq.heappush(minHeap, (0, 0, 0)) # (distance, row, col)

directions = [(-1, 0), (1, 0), (0, -1), (0, 1)]
visited = set()
dp = [[2**31]*col for i in range(row)]

while minHeap:
d, r, c = heapq.heappop(minHeap)
if (r, c) in visited: continue
visited.add((r,c))
dp[r][c] = d
if r == row-1 and c == col-1: return dp[r][c]
for direc in directions:
nr = r + direc[0]
nc = c + direc[1]
if 0 <= nr < row and 0 <= nc < col:
nd = max(dp[r][c], abs(heights[r][c] - heights[nr][nc]))
if nd < dp[nr][nc]:
heapq.heappush(minHeap, (nd, nr, nc))

return 0

# Time: O(r*c * log(r*c))
# Space: O(r * c)


'''
# Method 2 --------> using Binary Search
class Solution:
def minimumEffortPath(self, heights: List[List[int]]) -> int:
'''
22 changes: 22 additions & 0 deletions 12_Backtracking/18. Fair Distribution of Cookies.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# https://leetcode.com/problems/fair-distribution-of-cookies/

class Solution:
def distributeCookies(self, cookies: List[int], k: int) -> int:
self.res = 2**31
children = [0] * k
def dfs(i):
if i >= len(cookies):
self.res = min(self.res, max(children))
return
if max(children) > self.res: return
for j in range(k):
children[j] += cookies[i]
dfs(i+1)
children[j] -= cookies[i]

dfs(0)
return self.res

# Time: O(n^k)
# Space: O(k)

18 changes: 18 additions & 0 deletions 16_String/08. Subarray Product Less Than K.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# https://leetcode.com/problems/subarray-product-less-than-k/

class Solution:
def numSubarrayProductLessThanK(self, nums: List[int], k: int) -> int:
l = 0
p = 1
res = 0
for r in range(len(nums)):
p *= nums[r]
while l <= r and p >= k:
p //= nums[l]
l += 1
res += r - l + 1

return res

# Time: O(N)
# Space: O(1)
Loading

0 comments on commit 4cae70d

Please sign in to comment.