diff --git a/challenge-01/README.md b/challenge-01/README.md new file mode 100644 index 0000000..fe3b594 --- /dev/null +++ b/challenge-01/README.md @@ -0,0 +1,6 @@ +## Personal Information +### Name +Khalid Adeel p + +### Email +adeelpv360@gmail.com \ No newline at end of file diff --git a/challenge-01/two-sum.py b/challenge-01/two-sum.py new file mode 100644 index 0000000..4764c9e --- /dev/null +++ b/challenge-01/two-sum.py @@ -0,0 +1,8 @@ +class Solution: + def twoSum(self, nums: List[int], target: int) -> List[int]: + num_indices = {} + for i,num in enumerate(nums): + difference = target - num + if difference in num_indices: + return [num_indices[difference], i] + num_indices[num]=i \ No newline at end of file diff --git a/challenge-02/best-time-to-buy-and-sell-stoc.py b/challenge-02/best-time-to-buy-and-sell-stoc.py new file mode 100644 index 0000000..b1171de --- /dev/null +++ b/challenge-02/best-time-to-buy-and-sell-stoc.py @@ -0,0 +1,13 @@ +class Solution: + def maxProfit(self, prices: List[int]) -> int: + right, left = 1, 0 + profit = 0 + + while right < len(prices): + if prices[right] > prices[left]: + if profit < (prices[right] - prices[left]): + profit = prices[right] - prices[left] + else: + left = right + right +=1 + return profit \ No newline at end of file diff --git a/challenge-03/contains-duplicate.py b/challenge-03/contains-duplicate.py new file mode 100644 index 0000000..6af9833 --- /dev/null +++ b/challenge-03/contains-duplicate.py @@ -0,0 +1,9 @@ +class Solution: + def containsDuplicate(self, nums: List[int]) -> bool: + array = set() + for i in nums: + if i in array: + return True + else: + array.add(i) + return False \ No newline at end of file diff --git a/challenge-04/sum-of-two-integers.py b/challenge-04/sum-of-two-integers.py new file mode 100644 index 0000000..4218d21 --- /dev/null +++ b/challenge-04/sum-of-two-integers.py @@ -0,0 +1,8 @@ +class Solution: + def getSum(self, a: int, b: int) -> int: + mask = 0xffffffff + while (mask&b) > 0: + a, b = a ^ b, (a&b)<<1 + return (mask&a) if b > 0 else a + + \ No newline at end of file diff --git a/challenge-05/product-of-array-except-self.py b/challenge-05/product-of-array-except-self.py new file mode 100644 index 0000000..ae01631 --- /dev/null +++ b/challenge-05/product-of-array-except-self.py @@ -0,0 +1,12 @@ +class Solution: + def productExceptSelf(self, nums: List[int]) -> List[int]: + res = [1] * (len(nums)) + prefix = 1 + for i in range(len(nums)): + res[i] = prefix + prefix *= nums[i] + postfix = 1 + for i in range(len(nums) -1, -1, -1): + res[i] *= postfix + postfix *= nums[i] + return res diff --git a/challenge-06/maximum-product-subarray.py b/challenge-06/maximum-product-subarray.py new file mode 100644 index 0000000..d158a64 --- /dev/null +++ b/challenge-06/maximum-product-subarray.py @@ -0,0 +1,16 @@ +class Solution: + def maxProduct(self, nums: List[int]) -> int: + cur_min = 1 + cur_max = 1 + res = nums[0] + + for num in nums: + temp = cur_max * num + cur_max = max(temp, cur_min * num, num) + cur_min = min(temp, cur_min * num, num) + + res = max(res, cur_max) + + return res + + \ No newline at end of file diff --git a/challenge-07/maximum-subarray.py b/challenge-07/maximum-subarray.py new file mode 100644 index 0000000..708e41d --- /dev/null +++ b/challenge-07/maximum-subarray.py @@ -0,0 +1,12 @@ +class Solution: + def maxSubArray(self, nums: List[int]) -> int: + max_sum = nums[0] + cur_sum = 0 + + for i in nums: + if cur_sum < 0: + cur_sum = 0 + cur_sum += i + max_sum = max(max_sum, cur_sum) + + return max_sum \ No newline at end of file diff --git a/challenge-08/find-minimum-in-rotated-sorted-array.py b/challenge-08/find-minimum-in-rotated-sorted-array.py new file mode 100644 index 0000000..0286cde --- /dev/null +++ b/challenge-08/find-minimum-in-rotated-sorted-array.py @@ -0,0 +1,23 @@ +class Solution: + def findMin(self, nums: List[int]) -> int: + l = 0 + r = len(nums)-1 + res = nums[0] + + while l <= r: + if nums[l] < nums[r]: + res = min(res, nums[l]) + break + m = (l+r)//2 + res = min(res, nums[m]) + + if nums[l] <= nums[m]: + l = m+1 + else: + r = m-1 + + return res + + +# Time : O(LogN) +# Space : O(1) \ No newline at end of file diff --git a/challenge-09/search-in-rotated-sorted-array.py b/challenge-09/search-in-rotated-sorted-array.py new file mode 100644 index 0000000..346aa7e --- /dev/null +++ b/challenge-09/search-in-rotated-sorted-array.py @@ -0,0 +1,29 @@ +class Solution: + def search(self, nums: List[int], target: int) -> int: + l = 0 + r = len(nums) - 1 + + while l <= r: + mid = (l + r) // 2 + + if nums[mid] == target: + return mid + + # left sorted portion + elif nums[mid] >= nums[l]: + if nums[l] <= target <= nums[mid]: + r = mid - 1 + else: + l = mid + 1 + + # right sorted portion + else: + if nums[mid] <= target <= nums[r]: + l = mid + 1 + else: + r = mid - 1 + + return -1 + +# TC : O(LogN) +# SC : O(1) \ No newline at end of file diff --git a/challenge-10/3sum.py b/challenge-10/3sum.py new file mode 100644 index 0000000..2c2f223 --- /dev/null +++ b/challenge-10/3sum.py @@ -0,0 +1,30 @@ +class Solution: + def threeSum(self, nums: List[int]) -> List[List[int]]: + nums.sort() + res = [] + + for i in range(len(nums) - 2): + if i > 0 and nums[i] == nums[i-1]: + continue + l = i+1 + r = len(nums) - 1 + + while l < r: + total = nums[i] + nums[l] + nums[r] + if total < 0: + l +=1 + elif total > 0: + r -= 1 + else: + triplet = [nums[i], nums[l], nums[r]] + res.append(triplet) + while l < r and nums[l] == triplet[1]: + l += 1 + while l < r and nums[r] == triplet[2]: + r -= 1 + return res + + + +# TC : O(N^2) +# sc : o(1) \ No newline at end of file diff --git a/challenge-11/container-with-most-water.py b/challenge-11/container-with-most-water.py new file mode 100644 index 0000000..9fc65a9 --- /dev/null +++ b/challenge-11/container-with-most-water.py @@ -0,0 +1,22 @@ +class Solution: + def maxArea(self, height: List[int]) -> int: + l, r = 0, len(height) - 1 + maxArea = 0 + + while l < r: + if height[l] > height[r]: + h = height[r] + w = r - l + area = h * w + r -= 1 + else: + h = height[l] + w = r - l + area = h * w + l += 1 + maxArea = max(area, maxArea) + return maxArea + + +# TC : O(N) +# SC : O(1) \ No newline at end of file diff --git a/challenge-12/number-of-1-bits.py b/challenge-12/number-of-1-bits.py new file mode 100644 index 0000000..db1b1e8 --- /dev/null +++ b/challenge-12/number-of-1-bits.py @@ -0,0 +1,9 @@ +class Solution: + def hammingWeight(self, n: int) -> int: + bit = list(bin(n)) + count = 0 + for i in range(len(bit)): + if bit[i] == '1': + count += 1 + return count + diff --git a/challenge-13/counting-bits.py b/challenge-13/counting-bits.py new file mode 100644 index 0000000..253fb66 --- /dev/null +++ b/challenge-13/counting-bits.py @@ -0,0 +1,10 @@ +class Solution: + def countBits(self, n: int) -> List[int]: + ans = [0] * (n+1) + for i in range(1, n + 1): + ans[i] = ans[i >> 1] + (i & 1) + + return ans + +# TC : O(N) +# SC : O(N) \ No newline at end of file diff --git a/challenge-14/missing-number.py b/challenge-14/missing-number.py new file mode 100644 index 0000000..c67da6f --- /dev/null +++ b/challenge-14/missing-number.py @@ -0,0 +1,10 @@ +class Solution: + def missingNumber(self, nums: List[int]) -> int: + value = len(nums) + + for i, num in enumerate(nums): + value ^= i ^ num + return value + +# TC : O(N) +# SC : O(1) \ No newline at end of file diff --git a/challenge-15/reverse-bits.py b/challenge-15/reverse-bits.py new file mode 100644 index 0000000..65a2902 --- /dev/null +++ b/challenge-15/reverse-bits.py @@ -0,0 +1,11 @@ +class Solution: + def reverseBits(self, n: int) -> int: + res = 0 + for i in range(32): + res <<=1 + res |= (n&1) + n >>= 1 + return res + +# TC : O(1) +# SC : O(1) \ No newline at end of file diff --git a/challenge-16/climbing-stairs.py b/challenge-16/climbing-stairs.py new file mode 100644 index 0000000..e1d9768 --- /dev/null +++ b/challenge-16/climbing-stairs.py @@ -0,0 +1,12 @@ +class Solution: + def climbStairs(self, n: int) -> int: + a, b = 1, 1 + + for i in range(n - 2, -1, -1): + c = a+b + a = b + b = c + return b + +# TC : O(N) +# SC : O(1) \ No newline at end of file diff --git a/challenge-17/coin-change.py b/challenge-17/coin-change.py new file mode 100644 index 0000000..15bf400 --- /dev/null +++ b/challenge-17/coin-change.py @@ -0,0 +1,15 @@ +class Solution: + def coinChange(self, coins: List[int], amount: int) -> int: + dp = [amount + 1] * (amount + 1) + dp[0] = 0 + + for value in range(1, amount + 1): + for c in coins: + if value - c >= 0: + dp[value] = min(dp[value], 1 + dp[value - c]) + + return dp[amount] if dp[amount] != amount + 1 else -1 + + +# TC : O(N∗Amount) +# SC : O(Amount) \ No newline at end of file diff --git a/challenge-18/longest-increasing-subsequence.py b/challenge-18/longest-increasing-subsequence.py new file mode 100644 index 0000000..447920c --- /dev/null +++ b/challenge-18/longest-increasing-subsequence.py @@ -0,0 +1,17 @@ +class Solution: + def lengthOfLIS(self, nums: List[int]) -> int: + if not nums: + return 0 + + l = len(nums) + dp = [1] * l + + for i in range(1, l): + for j in range(i): + if nums[i] > nums[j]: + dp[i] = max(dp[i], dp[j] + 1) + + return max(dp) + +# TC : O(N^2) +# SC : O(N) \ No newline at end of file diff --git a/challenge-19/longest-common-subsequence.py b/challenge-19/longest-common-subsequence.py new file mode 100644 index 0000000..9e238c7 --- /dev/null +++ b/challenge-19/longest-common-subsequence.py @@ -0,0 +1,14 @@ +class Solution: + def longestCommonSubsequence(self, text1: str, text2: str) -> int: + c = [[0 for j in range(len(text2)+1)] for i in range(len(text1)+1)] + for i in range(len(text1)-1, -1, -1): + for j in range(len(text2)-1, -1, -1): + if text1[i] == text2[j]: + c[i][j] = 1 + c[i+1][j+1] + else: + c[i][j] = max(c[i][j+1], c[i+1][j]) + ans = c[i][j] + return ans + +# TC : O(N^2) +# SC : O(N^2) \ No newline at end of file diff --git a/challenge-20/word-break.py b/challenge-20/word-break.py new file mode 100644 index 0000000..c937826 --- /dev/null +++ b/challenge-20/word-break.py @@ -0,0 +1,20 @@ +class Solution: + def wordBreak(self, s: str, wordDict: List[str]) -> bool: + def construct(current, wordDict, memo={}): + if current in memo: + return memo[current] + + if not current: + return True + + for word in wordDict: + if current.startswith(word): + new_current = current[len(word):] + if construct(new_current, wordDict, memo): + memo[current] = True + return True + + memo[current] = False + return False + + return construct(s,wordDict) \ No newline at end of file diff --git a/challenge-21/combination-sum-iv.py b/challenge-21/combination-sum-iv.py new file mode 100644 index 0000000..01485c8 --- /dev/null +++ b/challenge-21/combination-sum-iv.py @@ -0,0 +1,14 @@ +class Solution: + def combinationSum4(self, nums: List[int], target: int): + dp = [0] * (target + 1) + dp[0] = 1 + + for i in range(1, target + 1): + for num in nums: + if i - num >= 0: + dp[i] += dp[i - num] + + return dp[target] + +# TC : O(Target * N) +# SC : O(Target) \ No newline at end of file diff --git a/challenge-22/house-robber.py b/challenge-22/house-robber.py new file mode 100644 index 0000000..87dcf96 --- /dev/null +++ b/challenge-22/house-robber.py @@ -0,0 +1,13 @@ +class Solution: + def rob(self, nums: List[int]) -> int: + rob1 = rob2 = 0 + + for val in nums: + decision = max(val + rob1, rob2) + rob1 = rob2 + rob2 = decision + + return rob2 + +# TC : O(N) +# SC : O(1) \ No newline at end of file diff --git a/challenge-23/house-robber-ii.py b/challenge-23/house-robber-ii.py new file mode 100644 index 0000000..fbb1dfd --- /dev/null +++ b/challenge-23/house-robber-ii.py @@ -0,0 +1,23 @@ +class Solution: + def rob(self, nums: List[int]) -> int: + + if len(nums) == 1: + return nums[0] + if len(nums) == 2: + return max(nums[0], nums[1]) + if len(nums) == 3: + return max(nums[0], nums[1], nums[2]) + + return max(nums[0], self.helper(nums[1:]), self.helper(nums[:-1])) + + def helper(self, nums): + rob1 = rob2 = 0 + for val in nums: + decision = max(val + rob1, rob2) + rob1 = rob2 + rob2 = decision + + return rob2 + +# TC : O(N) +# SC : O(1) \ No newline at end of file diff --git a/challenge-24/decode-ways.py b/challenge-24/decode-ways.py new file mode 100644 index 0000000..3be3a2a --- /dev/null +++ b/challenge-24/decode-ways.py @@ -0,0 +1,21 @@ +class Solution: + def numDecodings(self, s: str) -> int: + dp = {len(s): 1} + + def bfs(i): + if i in dp: + return dp[i] + if s[i] == "0": + return 0 + + res = bfs(i+1) + + if (i+1 < len(s) and (s[i] == "1" or s[i] == "2" and s[i+1] in "0123456")): + res += bfs(i+2) + + dp[i] = res + return res + return bfs(0) + +# TC : O(N) +# SC : O(N) \ No newline at end of file diff --git a/challenge-25/unique-paths.py b/challenge-25/unique-paths.py new file mode 100644 index 0000000..91d5f1b --- /dev/null +++ b/challenge-25/unique-paths.py @@ -0,0 +1,13 @@ +class Solution: + def uniquePaths(self, m: int, n: int) -> int: + dp = [[0]*n]*m + for i in range(0,m): + for j in range(0,n): + if i == 0 or j == 0: + dp[i][j] = 1 + else: + dp[i][j] = dp[i-1][j] + dp[i][j-1] + return dp[m-1][n-1] + +# TC : O(M * N) +# SC : O(M * N) \ No newline at end of file diff --git a/challenge-26/jump-game.py b/challenge-26/jump-game.py new file mode 100644 index 0000000..d41f4c2 --- /dev/null +++ b/challenge-26/jump-game.py @@ -0,0 +1,13 @@ +class Solution: + def canJump(self, nums: List[int]) -> bool: + i = 0 + for n in nums: + if i < 0: + return False + elif n > i: + i = n + i -= 1 + return True + +# TC : O(N) +# SC : O(1) \ No newline at end of file diff --git a/challenge-27/clone-graph.py b/challenge-27/clone-graph.py new file mode 100644 index 0000000..712d86f --- /dev/null +++ b/challenge-27/clone-graph.py @@ -0,0 +1,30 @@ +""" +# Definition for a Node. +class Node: + def __init__(self, val = 0, neighbors = None): + self.val = val + self.neighbors = neighbors if neighbors is not None else [] +""" + +from typing import Optional +class Solution: + def cloneGraph(self, node: Optional['Node']) -> Optional['Node']: + oldtonew = dict() + + def dfs(node): + if not node: + return + if node in oldtonew: + return oldtonew[node] + + copy = Node(node.val) + oldtonew[node] = copy + + for nei in node.neighbors: + copy_nei = dfs(nei) + copy.neighbors.append(copy_nei) + return copy + return dfs(node) + +# TC : O(N) +# SC : O(N) \ No newline at end of file diff --git a/challenge-28/course-schedule.py b/challenge-28/course-schedule.py new file mode 100644 index 0000000..2d18a4b --- /dev/null +++ b/challenge-28/course-schedule.py @@ -0,0 +1,33 @@ +from typing import List + +class Solution: + def dfs(self, i: int, adj: List[List[int]], hash: set, visited: List[bool]) -> bool: + hash.add(i) + visited[i] = True + + for neighbor in adj[i]: + if not visited[neighbor]: + if not self.dfs(neighbor, adj, hash, visited): + return False + elif neighbor in hash: + return False + + hash.remove(i) + return True + + def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool: + adj = [[] for _ in range(numCourses)] + for dest, src in prerequisites: + adj[src].append(dest) + + visited = [False] * numCourses + for i in range(numCourses): + if not visited[i]: + hash = set() + if not self.dfs(i, adj, hash, visited): + return False + + return True + +# TC : O(V + E) +# SC : O(V) \ No newline at end of file diff --git a/challenge-29/pacific-atlantic-water-flow.py b/challenge-29/pacific-atlantic-water-flow.py new file mode 100644 index 0000000..18d682e --- /dev/null +++ b/challenge-29/pacific-atlantic-water-flow.py @@ -0,0 +1,48 @@ +class Solution: + def pacificAtlantic(self, grid: List[List[int]]) -> List[List[int]]: + R=len(grid) + C=len(grid[0]) + res=[] + pacific=[] + atlantic=[] + + #right and left side + for r in range(R): + pacific.append((r,0,grid[r][0])) + atlantic.append((r,C-1,grid[r][C-1])) + #north and south side + for c in range(C): + pacific.append((0,c,grid[0][c])) + atlantic.append((R-1,c,grid[R-1][c])) + + #pacific bfs + pacific_reach=set() + while pacific: + r, c, h = pacific.pop() + if (r, c) in pacific_reach: + continue + pacific_reach.add((r, c)) + nei = [[r+1, c], [r-1, c], [r, c+1], [r, c-1]] + for nr, nc in nei: + if 0 <= nr < R and 0 <= nc < C and grid[nr][nc] >= h: + pacific.append((nr, nc, grid[nr][nc])) + + + #atlantic bfs + atlantic_reach=set() + while atlantic: + r, c, h = atlantic.pop() + if (r, c) in atlantic_reach: + continue + atlantic_reach.add((r, c)) + nei = [[r+1, c], [r-1, c], [r, c+1], [r, c-1]] + for nr, nc in nei: + if 0 <= nr < R and 0 <= nc < C and grid[nr][nc] >= h: + atlantic.append((nr, nc, grid[nr][nc])) + for r,c in pacific_reach: + if (r,c) in atlantic_reach: + res.append((r,c)) + return res + +# TC : O(R * C) +# SC : O(R * C) \ No newline at end of file diff --git a/challenge-30/number-of-islands.py b/challenge-30/number-of-islands.py new file mode 100644 index 0000000..7751659 --- /dev/null +++ b/challenge-30/number-of-islands.py @@ -0,0 +1,37 @@ +class Solution: + def numIslands(self, grid: List[List[str]]) -> int: + if not grid: + return 0 + islands = 0 + rows, cols = len(grid), len(grid[0]) + + def bfs(r, c): + q = deque() + q.append((r,c)) + grid[r][c] = '0' + + while q: + row, col = q.popleft() + directions = [[1,0], [-1,0], [0,1], [0,-1]] + + for dr, dc in directions: + r, c = row + dr, col + dc + + if ((0<= r < rows) and + (0 <= c < cols) and + grid[r][c] == '1' and + (r,c)): + q.append((r,c)) + grid[r][c] = '0' + + for r in range(rows): + for c in range(cols): + if grid[r][c] == '1' and (r,c): + bfs(r,c) + islands += 1 + + + return islands + +# TC : O(Rows∗Cols) +# SC : O(Rows∗Cols) \ No newline at end of file diff --git a/challenge-31/longest-consecutive-sequence.py b/challenge-31/longest-consecutive-sequence.py new file mode 100644 index 0000000..cac7af9 --- /dev/null +++ b/challenge-31/longest-consecutive-sequence.py @@ -0,0 +1,18 @@ +class Solution: + def longestConsecutive(self, nums: List[int]) -> int: + num_set = set(nums) + longest = 0 + + for n in num_set: + if n - 1 not in num_set: + length = 1 + + while n + length in num_set: + length += 1 + + longest = max(longest, length) + + return longest + +# TC : O(N) +# SC : O(N) \ No newline at end of file diff --git a/challenge-32/find-building-where-alice-and-bob-can-meet.py b/challenge-32/find-building-where-alice-and-bob-can-meet.py new file mode 100644 index 0000000..68a0ffb --- /dev/null +++ b/challenge-32/find-building-where-alice-and-bob-can-meet.py @@ -0,0 +1,21 @@ +class Solution: + def leftmostBuildingQueries(self, heights: List[int], queries: List[List[int]]) -> List[int]: + def leftmostBuildingQueries(self, A, queries): + que = [[] for a in A] + h = [] + res = [-1] * len(queries) + for qi, (i, j) in enumerate(queries): + if cmp(i, j) == cmp(A[i], A[j]): + res[qi] = max(i, j) + else: + que[max(i, j)].append([max(A[i], A[j]), qi]) + for i, a in enumerate(A): + while h and h[0][0] < a: + res[heappop(h)[1]] = i + for q in que[i]: + heappush(h, q) + return res + +# TC : O(qlogq) +# SC : O(Q) +# where q is size of query \ No newline at end of file diff --git a/challenge-33/maximum-star-sum-of-a-graph.py b/challenge-33/maximum-star-sum-of-a-graph.py new file mode 100644 index 0000000..4c439a0 --- /dev/null +++ b/challenge-33/maximum-star-sum-of-a-graph.py @@ -0,0 +1,34 @@ +import heapq +class Solution: + def maxStarSum(self, vals: List[int], edges: List[List[int]], k: int) -> int: + # build edges for each value : [for each index: [value of neighbors]] + neighbors = [[] for _ in vals] + + for left, right in edges: + neighbors[left].append(-vals[right]) + neighbors[right].append(-vals[left]) + + for sublist in neighbors: + heapq.heapify(sublist) + + # can try a combo for each vertex + max_val = float("-inf") + + for i, sublist in enumerate(neighbors): + curr = vals[i] + for i in range(k): + if sublist: + to_add = heapq.heappop(sublist) + if to_add >= 0: + break + curr -= to_add + else: + break + + + max_val = max(max_val, curr) + + return max_val if max_val != float("-inf") else 0 + +# TC : O(E + k * V) +# SC : O(E) diff --git a/challenge-34/count-unreachable-pairs-of-nodes-in-an-undirected-graph.py b/challenge-34/count-unreachable-pairs-of-nodes-in-an-undirected-graph.py new file mode 100644 index 0000000..4d88d03 --- /dev/null +++ b/challenge-34/count-unreachable-pairs-of-nodes-in-an-undirected-graph.py @@ -0,0 +1,28 @@ +class Solution: + def countPairs(self, n: int, edges: List[List[int]]) -> int: + def dfs(node): + if visited[node]: + return 0 + visited[node] = True + res = 1 + for nbr in graph[node]: + res += dfs(nbr) + return res + graph = {} + for i in range(n): + graph[i] = [] + for edge in edges: + graph[edge[0]].append(edge[1]) + graph[edge[1]].append(edge[0]) + + visited = [False for _ in range(n)] + components = [] + for node in range(n): + if visited[node] == False: + components.append(dfs(node)) + + ans = n * (n - 1) // 2 + for k in components: + ans -= k * (k - 1) // 2 + + return ans \ No newline at end of file diff --git a/challenge-35/insert-interval.py b/challenge-35/insert-interval.py new file mode 100644 index 0000000..a2b5439 --- /dev/null +++ b/challenge-35/insert-interval.py @@ -0,0 +1,17 @@ +class Solution: + def insert(self, intervals: List[List[int]], newInterval: List[int]) -> List[List[int]]: + intervals.append(newInterval) + intervals.sort() + + res = [intervals[0]] + + for i in range(1, len(intervals)): + if res[-1][1] >= intervals[i][0]: + res[-1][1] = max(res[-1][1], intervals[i][1]) + else: + res.append(intervals[i]) + + return res + +# TC : O(NlogN) +# SC : O(sort) \ No newline at end of file diff --git a/challenge-36/merge-intervals.py b/challenge-36/merge-intervals.py new file mode 100644 index 0000000..5cb55cd --- /dev/null +++ b/challenge-36/merge-intervals.py @@ -0,0 +1,20 @@ +class Solution: + def merge(self, intervals: List[List[int]]) -> List[List[int]]: + merged = [] + intervals.sort(key=lambda x: x[0]) + + prev = intervals[0] + + for interval in intervals[1:]: + if interval[0] <= prev[1]: + prev[1] = max(prev[1], interval[1]) + else: + merged.append(prev) + prev = interval + + merged.append(prev) + + return merged + +# TC : O(NlogN) +# SC : O(N) \ No newline at end of file diff --git a/challenge-37/non-overlapping-intervals.py b/challenge-37/non-overlapping-intervals.py new file mode 100644 index 0000000..3cc5d91 --- /dev/null +++ b/challenge-37/non-overlapping-intervals.py @@ -0,0 +1,13 @@ +class Solution(object): + def eraseOverlapIntervals(self, intervals): + intervals.sort(key=lambda x: x[1]) + non_overlapping = 0 + prev_end = float('-inf') + for start, end in intervals: + if start >= prev_end: + non_overlapping += 1 + prev_end = end + return len(intervals) - non_overlapping + +# TC : O(NlogN) +# SC : O(1) \ No newline at end of file diff --git a/challenge-38/meeting-schedule.py b/challenge-38/meeting-schedule.py new file mode 100644 index 0000000..d5b3b16 --- /dev/null +++ b/challenge-38/meeting-schedule.py @@ -0,0 +1,21 @@ +""" +Definition of Interval: +class Interval(object): + def __init__(self, start, end): + self.start = start + self.end = end +""" + +class Solution: + def canAttendMeetings(self, intervals: List[Interval]) -> bool: + n = len(intervals) + for i in range(n): + A = intervals[i] + for j in range(i + 1, n): + B = intervals[j] + if min(A.end, B.end) > max(A.start, B.start): + return False + return True + +# TC : O(N^2) +# SC : O(1) \ No newline at end of file diff --git a/challenge-39/meeting-schedule-ii.py b/challenge-39/meeting-schedule-ii.py new file mode 100644 index 0000000..83e9d08 --- /dev/null +++ b/challenge-39/meeting-schedule-ii.py @@ -0,0 +1,22 @@ +""" +Definition of Interval: +class Interval(object): + def __init__(self, start, end): + self.start = start + self.end = end +""" + +class Solution: + def minMeetingRooms(self, intervals: List[Interval]) -> int: + intervals.sort(key=lambda x: x.start) + min_heap = [] + + for interval in intervals: + if min_heap and min_heap[0] <= interval.start: + heapq.heappop(min_heap) + heapq.heappush(min_heap, interval.end) + + return len(min_heap) + +# TC : O(NlogN) +# SC : O(N) \ No newline at end of file diff --git a/challenge-40/reverse-linked-list.py b/challenge-40/reverse-linked-list.py new file mode 100644 index 0000000..90a07a7 --- /dev/null +++ b/challenge-40/reverse-linked-list.py @@ -0,0 +1,27 @@ +# Definition for singly-linked list. +class ListNode: + def __init__(self, val=0, next=None): + self.val = val + self.next = next +class Solution: + def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: + p = None + c = head + + if not head: + return + + while c: + n = c.next + c.next = p + p = c + c = n + if c: + n = c.next + + head = p + + return head + +# TC : O(N) +# SC : O(1) \ No newline at end of file diff --git a/challenge-41/linked-list-cycle.cpp b/challenge-41/linked-list-cycle.cpp new file mode 100644 index 0000000..1d26c30 --- /dev/null +++ b/challenge-41/linked-list-cycle.cpp @@ -0,0 +1,26 @@ +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode(int x) : val(x), next(NULL) {} + * }; + */ + class Solution { + public: + bool hasCycle(ListNode *head) { + ListNode *f = head; + ListNode *s = head; + + while(f && f->next) { + s = s->next; + f = f->next->next; + + if (f == s) { + return true; + } + } + return false; + } + }; + diff --git a/challenge-41/linked-list-cycle.py b/challenge-41/linked-list-cycle.py new file mode 100644 index 0000000..5c0c62e --- /dev/null +++ b/challenge-41/linked-list-cycle.py @@ -0,0 +1,22 @@ +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, x): +# self.val = x +# self.next = None + +class Solution: + def hasCycle(self, head: Optional[ListNode]) -> bool: + f = head + s = head + + while f and f.next: + s = s.next + f = f.next.next + + if f == s: + return True + + return False + +# TC : O(N) +# SC : O(1) \ No newline at end of file diff --git a/challenge-42/merge-two-sorted-lists.py b/challenge-42/merge-two-sorted-lists.py new file mode 100644 index 0000000..e1468fd --- /dev/null +++ b/challenge-42/merge-two-sorted-lists.py @@ -0,0 +1,18 @@ +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution: + def mergeTwoLists(self, list1: Optional[ListNode], list2: Optional[ListNode]) -> Optional[ListNode]: + if not list1 or not list2: + return list1 if list1 else list2 + + if list1.val > list2.val: + list1, list2 = list2, list1 + + list1.next = self.mergeTwoLists(list1.next, list2) + return list1 + +# TC : O(N + M) +# SC : O(N + M) \ No newline at end of file diff --git a/challenge-43/merge-k-sorted-lists.py b/challenge-43/merge-k-sorted-lists.py new file mode 100644 index 0000000..92653f7 --- /dev/null +++ b/challenge-43/merge-k-sorted-lists.py @@ -0,0 +1,34 @@ +class Solution: + def mergeKLists(self, lists: List[Optional[ListNode]]) -> Optional[ListNode]: + if not lists or len(lists) == 0: + return None + + while len(lists) > 1: + temp = [] + for i in range(0, len(lists), 2): + l1 = lists[i] + l2 = lists[i+1] if i + 1 < len(lists) else None + temp.append(self.merge_lists(l1, l2)) + lists = temp + + return lists[0] + + def merge_lists(self, l1, l2): + node = ListNode() + ans = node + + while l1 and l2: + if l1.val > l2.val: + node.next = l2 + l2 = l2.next + else: + node.next = l1 + l1 = l1.next + node = node.next + + if l1: + node.next = l1 + else: + node.next = l2 + + return ans.next \ No newline at end of file diff --git a/challenge-44/remove-nth-node-from-end-of-list.py b/challenge-44/remove-nth-node-from-end-of-list.py new file mode 100644 index 0000000..c85b8ce --- /dev/null +++ b/challenge-44/remove-nth-node-from-end-of-list.py @@ -0,0 +1,18 @@ +class Solution: + def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]: + res = ListNode(0, head) + dummy = res + + for _ in range(n): + head = head.next + + while head: + head = head.next + dummy = dummy.next + + dummy.next = dummy.next.next + + return res.next + +# TC : O(N) +# SC : O(1) \ No newline at end of file diff --git a/challenge-45/reorder-list.py b/challenge-45/reorder-list.py new file mode 100644 index 0000000..524bb5f --- /dev/null +++ b/challenge-45/reorder-list.py @@ -0,0 +1,35 @@ +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution: + def reorderList(self, head: Optional[ListNode]) -> None: + """ + Do not return anything, modify head in-place instead. + """ + if not head or not head.next: + return + + slow, fast = head, head + while fast and fast.next: + slow = slow.next + fast = fast.next.next + + prev, curr = None, slow.next + slow.next = None + while curr: + temp = curr.next + curr.next = prev + prev = curr + curr = temp + + first, second = head, prev + while second: + temp1, temp2 = first.next, second.next + first.next = second + second.next = temp1 + first, second = temp1, temp2 + +# TC : O(N) +# SC : O(1) \ No newline at end of file diff --git a/challenge-46/set-matrix-zeroes.py b/challenge-46/set-matrix-zeroes.py new file mode 100644 index 0000000..034afc2 --- /dev/null +++ b/challenge-46/set-matrix-zeroes.py @@ -0,0 +1,50 @@ +class Solution: + def setZeroes(self, matrix: List[List[int]]) -> None: + """ + Do not return anything, modify matrix in-place instead. + """ + rows = len(matrix) + column = len(matrix[0]) + + first_row_zero = False + first_col_zero = False + + # check if the first column contains zero + for r in range(rows): + if matrix[r][0] == 0: + first_col_zero = True + break + + # check if the first row contains zero + for c in range(column): + if matrix[0][c] == 0: + first_row_zero = True + break + + # set first column and row as zero + for row in range(1, rows): + for col in range(1, column): + if matrix[row][col] == 0: + matrix[row][0] = 0 + matrix[0][col] = 0 + + for row in range(1, rows): + if matrix[row][0] == 0: + for col in range(1, column): + matrix[row][col] = 0 + + for col in range(1, column): + if matrix[0][col] == 0: + for row in range(1, rows): + matrix[row][col] = 0 + + if first_row_zero: + for c in range(column): + matrix[0][c] = 0 + + if first_col_zero: + for r in range(rows): + matrix[r][0] = 0 + +# TC : O(M * N) +# SC : O(1) \ No newline at end of file diff --git a/challenge-47/spiral-matrix.py b/challenge-47/spiral-matrix.py new file mode 100644 index 0000000..736d622 --- /dev/null +++ b/challenge-47/spiral-matrix.py @@ -0,0 +1,21 @@ +class Solution: + def spiralOrder(self, matrix: List[List[int]]) -> List[int]: + rows = len(matrix) + cols = len(matrix[0]) + res = [] + c, r, dc, dr = 0, 0, 1, 0 + + for _ in range(rows * cols): + res.append(matrix[r][c]) + matrix[r][c] = "." + + if not 0 <= c + dc < cols or not 0 <= r + dr < rows or matrix[r+dr][c+dc] == ".": + dc, dr = -dr, dc + + c += dc + r += dr + + return res + +# TC : O(M * N) +# SC O(1) \ No newline at end of file diff --git a/challenge-48/rotate-image.py b/challenge-48/rotate-image.py new file mode 100644 index 0000000..09a80be --- /dev/null +++ b/challenge-48/rotate-image.py @@ -0,0 +1,23 @@ +class Solution: + def rotate(self, matrix: List[List[int]]) -> None: + """ + Do not return anything, modify matrix in-place instead. + """ + n = len(matrix) + top = 0 + bottom = n-1 + + # vertical revers + while top < bottom: + for col in range(n): + matrix[top][col], matrix[bottom][col] = matrix[bottom][col], matrix[top][col] + top += 1 + bottom -= 1 + + # transpose + for row in range(n): + for col in range(row+1, n): + matrix[row][col], matrix[col][row] = matrix[col][row], matrix[row][col] + +# TC : O(N^2) +# SC : O(1) \ No newline at end of file diff --git a/challenge-49/word-search.py b/challenge-49/word-search.py new file mode 100644 index 0000000..7a61d48 --- /dev/null +++ b/challenge-49/word-search.py @@ -0,0 +1,40 @@ +class Solution: + def exist(self, board: List[List[str]], word: str) -> bool: + rows = len(board) + cols = len(board[0]) + N = len(word) + + def dfs(row, col, dept): + if dept == N: + return True + + if row >= rows or row < 0 \ + or col >= cols or col < 0 \ + or board[row][col] != word[dept]: + return False + + temp = board[row][col] + board[row][col] = "#" + + res = (dfs(row+1, col, dept+1) or + dfs(row-1, col, dept+1) or + dfs(row, col+1, dept+1) or + dfs(row, col-1, dept+1)) + board[row][col] = temp + + return res + + + + for r in range(rows): + for c in range(cols): + if word[0] == board[r][c]: + if dfs(r,c, 0): + return True + + return False + + +# TC : O(Row * Col * 3^L) +# SC : O(L) +# where L is the length of word \ No newline at end of file diff --git a/challenge-50/longest-substring-without-repeating-characters.py b/challenge-50/longest-substring-without-repeating-characters.py new file mode 100644 index 0000000..d351a64 --- /dev/null +++ b/challenge-50/longest-substring-without-repeating-characters.py @@ -0,0 +1,18 @@ +class Solution: + def lengthOfLongestSubstring(self, s: str) -> int: + visited = set() + left = 0 + max_len = 0 + for right in range(len(s)): + while s[right] in visited: + visited.remove(s[left]) + left += 1 + + visited.add(s[right]) + max_len = max(max_len, right - left+1) + + return max_len + +# TC : O(N) +# SC : O(min(m, n)) +# where m = len(s) and n = len(visited) \ No newline at end of file diff --git a/challenge-51/longest-repeating-character-replacement.py b/challenge-51/longest-repeating-character-replacement.py new file mode 100644 index 0000000..c460402 --- /dev/null +++ b/challenge-51/longest-repeating-character-replacement.py @@ -0,0 +1,19 @@ +class Solution: + def characterReplacement(self, s: str, k: int) -> int: + max_count = 0 + left = 0 + counts = [0] * 26 + + for right in range(len(s)): + counts[ord(s[right]) - 65] += 1 + + while (right-left+1) - max(counts) > k: + counts[ord(s[left]) - 65] -= 1 + left += 1 + + max_count = max(max_count, (right-left+1)) + + return max_count + +# TC : O(N) +# SC : O1 \ No newline at end of file diff --git a/challenge-52/minimum-window-substring.py b/challenge-52/minimum-window-substring.py new file mode 100644 index 0000000..8250a0c --- /dev/null +++ b/challenge-52/minimum-window-substring.py @@ -0,0 +1,39 @@ +class Solution: + def minWindow(self, s: str, t: str) -> str: + l = 0 + r = 0 + freq = defaultdict(int) + N = len(s) + min_len = N+1 + min_l = 0 + + for ch in t: + freq[ch] += 1 + + required = len(freq) + matches = 0 + + for r in range(N): + freq[s[r]] -= 1 + + if freq[s[r]] == 0: + matches += 1 + + while required == matches: + if (r-l+1) < min_len: + min_len = r-l+1 + min_l = l + + if freq[s[l]] == 0: + matches -= 1 + + freq[s[l]] += 1 + + l += 1 + if min_len != N+1: + return s[min_l:min_l+min_len] + + return "" + +# TC : O(M+N) +# SC : O(alphabet) \ No newline at end of file diff --git a/challenge-53/valid-anagram.py b/challenge-53/valid-anagram.py new file mode 100644 index 0000000..874de40 --- /dev/null +++ b/challenge-53/valid-anagram.py @@ -0,0 +1,8 @@ +from collections import Counter +class Solution: + def isAnagram(self, s: str, t: str) -> bool: + return Counter(s) == Counter(t) + + +# TC : O(N) +# SC : O(1) \ No newline at end of file diff --git a/challenge-54/group-anagrams.py b/challenge-54/group-anagrams.py new file mode 100644 index 0000000..772869a --- /dev/null +++ b/challenge-54/group-anagrams.py @@ -0,0 +1,16 @@ +class Solution: + def groupAnagrams(self, strs: List[str]) -> List[List[str]]: + d = {} + + for word in strs: + s_char = "".join(sorted(word)) + if s_char not in d: + d[s_char] = [word] + else: + d[s_char].append(word) + + + return list(d.values()) + +# TC : O(N * K Log K) +# SC : O( N * K) \ No newline at end of file diff --git a/challenge-55/valid-parentheses.py b/challenge-55/valid-parentheses.py new file mode 100644 index 0000000..0814fd5 --- /dev/null +++ b/challenge-55/valid-parentheses.py @@ -0,0 +1,22 @@ +class Solution: + def isValid(self, s: str) -> bool: + stack = [] + + op = { "[", "{", "(" } + + for i in range(len(s)): + if s[i] in op: + stack.append(s[i]) + else: + if not stack \ + or stack[-1] != "{" and s[i] == "}" \ + or stack[-1] != "[" and s[i] == "]" \ + or stack[-1] != "(" and s[i] == ")": + return False + stack.pop() + + + return not stack + +# TC : O(N) +# SC : O(N) \ No newline at end of file diff --git a/challenge-56/valid-palindrome.py b/challenge-56/valid-palindrome.py new file mode 100644 index 0000000..c978e4a --- /dev/null +++ b/challenge-56/valid-palindrome.py @@ -0,0 +1,17 @@ +class Solution: + def isPalindrome(self, s: str) -> bool: + s = ''.join(c.lower() for c in s if c.isalnum()) + + + l, r = 0, len(s) - 1 + while l < r: + if s[l] != s[r]: + return False + + l += 1 + r -= 1 + + return True + +# TC : O(N) +# SC : O(N) \ No newline at end of file diff --git a/challenge-57/longest-palindromic-substring.py b/challenge-57/longest-palindromic-substring.py new file mode 100644 index 0000000..54c38a8 --- /dev/null +++ b/challenge-57/longest-palindromic-substring.py @@ -0,0 +1,21 @@ +class Solution: + def longestPalindrome(self, s: str) -> str: + def expand(s, l, r): + while l >= 0 and r < len(s) and s[l] == s[r]: + l -= 1 + r += 1 + return r - l -1 + + left, right = 0, 0 + + for i in range(len(s)): + odd = expand(s, i, i) + even = expand(s, i, i+1) + max_len = max(odd, even) + + if max_len > right - left: + left = i - (max_len - 1) // 2 + right = i + max_len // 2 + + return s[left: right+1] + \ No newline at end of file diff --git a/challenge-58/palindromic-substrings.py b/challenge-58/palindromic-substrings.py new file mode 100644 index 0000000..9ad35f1 --- /dev/null +++ b/challenge-58/palindromic-substrings.py @@ -0,0 +1,21 @@ +class Solution: + def countSubstrings(self, s: str) -> int: + def expand(s, l, r, c = 0): + while l >= 0 and r < len(s) and s[l] == s[r]: + l -= 1 + r += 1 + c += 1 + return c + + count = 0 + + for i in range(len(s)): + even = expand(s, i, i+1) + odd = expand(s, i, i) + + count += even + odd + + return count + +# TC : O(N^2) +# SC : O(1) \ No newline at end of file diff --git a/challenge-59/string-encode-and-decode.py b/challenge-59/string-encode-and-decode.py new file mode 100644 index 0000000..ccc1dff --- /dev/null +++ b/challenge-59/string-encode-and-decode.py @@ -0,0 +1,47 @@ +class Solution: + def encode(self, strs: List[str]) -> str: + if not strs: + return "" + + size, res = [], "" + + for i in range(len(strs)): + size.append(len(strs[i])) + + for s in size: + res += str(s) + res += "," + + res += "#" + + for i in range(len(strs)): + res += strs[i] + + return res + + + def decode(self, s: str) -> List[str]: + if not s: + return [] + + size, i, res = [], 0, [] + + while s[i] != "#": + cur = "" + + while s[i] != ",": + cur += s[i] + i += 1 + size.append(int(cur)) + i += 1 + + i += 1 + + for sz in size: + res.append(s[i: i + sz]) + i += sz + + return res + +# TC : O(M) +# SC : O(M + N) \ No newline at end of file diff --git a/challenge-60/maximum-depth-of-binary-tree.py b/challenge-60/maximum-depth-of-binary-tree.py new file mode 100644 index 0000000..0d0ad6e --- /dev/null +++ b/challenge-60/maximum-depth-of-binary-tree.py @@ -0,0 +1,15 @@ +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def maxDepth(self, root: Optional[TreeNode]) -> int: + if not root: + return 0 + + return max(self.maxDepth(root.right), self.maxDepth(root.left)) + 1 + +# TC : O(N) +# SC : O(1) \ No newline at end of file diff --git a/challenge-61/same-tree.py b/challenge-61/same-tree.py new file mode 100644 index 0000000..45c1fb3 --- /dev/null +++ b/challenge-61/same-tree.py @@ -0,0 +1,22 @@ +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def isSameTree(self, p: Optional[TreeNode], q: Optional[TreeNode]) -> bool: + + if p == None and q == None: return True + if p == None or q == None: return False + + if p.val == q.val: + if self.isSameTree(p.left, q.left) and self.isSameTree(p.right, q.right): + return True + else: + return False + else: + return False + +# TC : O(N) +# SC : O(H) \ No newline at end of file diff --git a/challenge-62/invert-binary-tree.py b/challenge-62/invert-binary-tree.py new file mode 100644 index 0000000..67434b0 --- /dev/null +++ b/challenge-62/invert-binary-tree.py @@ -0,0 +1,19 @@ +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]: + if not root: + return root + root.left, root.right = root.right, root.left + + self.invertTree(root.left) + self.invertTree(root.right) + + return root + +# TC : O(N) +# SC : O(H) \ No newline at end of file diff --git a/challenge-63/binary-tree-maximum-path-sum.py b/challenge-63/binary-tree-maximum-path-sum.py new file mode 100644 index 0000000..45f90b7 --- /dev/null +++ b/challenge-63/binary-tree-maximum-path-sum.py @@ -0,0 +1,28 @@ +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def maxPathSum(self, root: Optional[TreeNode]) -> int: + res = [root.val] + + def helper(root): + if not root: + return 0 + + leftMax = helper(root.left) + rightMax = helper(root.right) + leftMax = max(0, leftMax) + rightMax = max(0, rightMax) + + res[0] = max(res[0], root.val + leftMax + rightMax) + + return root.val + max(leftMax, rightMax) + + helper(root) + return res[0] + +# TC : O(N) +# SC : O(H) \ No newline at end of file diff --git a/challenge-64/binary-tree-level-order-traversal.py b/challenge-64/binary-tree-level-order-traversal.py new file mode 100644 index 0000000..33d406f --- /dev/null +++ b/challenge-64/binary-tree-level-order-traversal.py @@ -0,0 +1,34 @@ +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def levelOrder(self, root: Optional[TreeNode]) -> List[List[int]]: + res = [] + + def bfs(c_node): + if not c_node: + return [] + q = deque() + q.append(c_node) + + while q: + n = len(q) + temp = [] + for _ in range(n): + node = q.popleft() + temp.append(node.val) + + if node.left: + q.append(node.left) + if node.right: + q.append(node.right) + res.append(temp) + bfs(root) + + return res + +# TC : O(N) +# SC : O(N) \ No newline at end of file diff --git a/challenge-65/serialize-and-deserialize-binary-tree.py b/challenge-65/serialize-and-deserialize-binary-tree.py new file mode 100644 index 0000000..38d6885 --- /dev/null +++ b/challenge-65/serialize-and-deserialize-binary-tree.py @@ -0,0 +1,63 @@ +# Definition for a binary tree node. +# class TreeNode(object): +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Codec: + + def serialize(self, root): + """Encodes a tree to a single string. + + :type root: TreeNode + :rtype: str + """ + if not root : + return "" + + self.ans = [] + + def traversal(node): + if node == None: + self.ans.append("null") + return + self.ans.append(str(node.val)) + traversal(node.left) + traversal(node.right) + traversal(root) + return ",".join(self.ans) + + def deserialize(self, data): + """Decodes your encoded data to tree. + + :type data: str + :rtype: TreeNode + """ + if len(data) == 0: + return [] + self.arr = data.split(",") + + def create(): + if not self.arr: + return None + val = self.arr.pop(0) + + if val == "null": + return None + + Node = TreeNode(val) + Node.left = create() + Node.right = create() + + return Node + return create() + + +# Your Codec object will be instantiated and called as such: +# ser = Codec() +# deser = Codec() +# ans = deser.deserialize(ser.serialize(root)) + +# TC : O(N) +# SC : O(N) \ No newline at end of file diff --git a/challenge-66/subtree-of-another-tree.py b/challenge-66/subtree-of-another-tree.py new file mode 100644 index 0000000..d68e2b5 --- /dev/null +++ b/challenge-66/subtree-of-another-tree.py @@ -0,0 +1,31 @@ +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def isSubtree(self, root: Optional[TreeNode], subRoot: Optional[TreeNode]) -> bool: + def isIdentical(t, s): + if not t and not s: + return True + if not t or not s: + return False + + if t.val != s.val: + return False + + return isIdentical(t.left, s.left) and isIdentical(t.right, s.right) + + def helper(t, s): + if not t: + return False + + if isIdentical(t, s): + return True + return helper(t.left, s) or helper(t.right, s) + + return helper(root, subRoot) + +# TC : O(N * M) +# SC : O(N + M) \ No newline at end of file diff --git a/challenge-67/construct-binary-tree-from-preorder-and-inorder-traversal.py b/challenge-67/construct-binary-tree-from-preorder-and-inorder-traversal.py new file mode 100644 index 0000000..f16c20b --- /dev/null +++ b/challenge-67/construct-binary-tree-from-preorder-and-inorder-traversal.py @@ -0,0 +1,27 @@ +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def buildTree(self, preorder: List[int], inorder: List[int]) -> Optional[TreeNode]: + preorder = deque(preorder) + mapping = {} + + for i in range(len(preorder)): + mapping[inorder[i]] = i + + def create(s, e): + if s > e: return None + + root = TreeNode(preorder.popleft()) + m = mapping[root.val] + root.left = create(s, m-1) + root.right = create(m+1, e) + return root + + return create(0, len(preorder)-1) + +# TC :O(N) +# SC :O(N) \ No newline at end of file diff --git a/challenge-68/validate-binary-search-tree.py b/challenge-68/validate-binary-search-tree.py new file mode 100644 index 0000000..45efab8 --- /dev/null +++ b/challenge-68/validate-binary-search-tree.py @@ -0,0 +1,23 @@ +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def isValidBST(self, root: Optional[TreeNode]) -> bool: + def check(node, minval, maxval): + if not node: + return True + + if not(minval < node.val < maxval): + return False + + left_bst = check(node.left, minval, node.val) + right_bst = check(node.right, node.val, maxval) + return left_bst and right_bst + + return check(root, float("-inf"), float("inf")) + +# TC : O(N) +# SC : O(N) \ No newline at end of file diff --git a/challenge-69/kth-smallest-element-in-a-bst.py b/challenge-69/kth-smallest-element-in-a-bst.py new file mode 100644 index 0000000..95cfce4 --- /dev/null +++ b/challenge-69/kth-smallest-element-in-a-bst.py @@ -0,0 +1,27 @@ +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def kthSmallest(self, root: Optional[TreeNode], k: int) -> int: + self.res = None + self.count = 0 + + def smallest(node): + if not node or self.res is not None: + return + + smallest(node.left) + self.count += 1 + if self.count == k: + self.res = node.val + return + + smallest(node.right) + smallest(root) + return self.res + +# TC : O(N) +# SC : O(H) \ No newline at end of file diff --git a/challenge-70/lowest-common-ancestor-of-a-binary-search-tree.py b/challenge-70/lowest-common-ancestor-of-a-binary-search-tree.py new file mode 100644 index 0000000..bb08ac8 --- /dev/null +++ b/challenge-70/lowest-common-ancestor-of-a-binary-search-tree.py @@ -0,0 +1,21 @@ +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution: + def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode': + + while root: + + if p.val < root.val and q.val < root.val: + root = root.left + elif p.val > root.val and q.val > root.val: + root = root.right + else: + return root + +# TC : O(H) +# SC : O(1) \ No newline at end of file diff --git a/challenge-71/implement-trie-prefix-tree.py b/challenge-71/implement-trie-prefix-tree.py new file mode 100644 index 0000000..badcc0c --- /dev/null +++ b/challenge-71/implement-trie-prefix-tree.py @@ -0,0 +1,42 @@ +from collections import defaultdict + +class TreeNode: + def __init__(self): + self.children = defaultdict(TreeNode) + self.is_end = False + +class Trie: + + def __init__(self): + self.trie = TreeNode() + + def insert(self, word: str) -> None: + node = self.trie + for c in word: + node = node.children[c] + node.is_end = True + + def search(self, word: str) -> bool: + node = self.find_word(word) + return node is not None and node.is_end + + def startsWith(self, prefix: str) -> bool: + return self.find_word(prefix) is not None + + def find_word(self, word: str): + node = self.trie + + for c in word: + if c not in node.children: + return None + node = node.children[c] + return node + +# Your Trie object will be instantiated and called as such: +# obj = Trie() +# obj.insert(word) +# param_2 = obj.search(word) +# param_3 = obj.startsWith(prefix) + +# TC : O(N) +# SC : O(K * N) \ No newline at end of file diff --git a/challenge-72/design-add-and-search-words-data-structure.py b/challenge-72/design-add-and-search-words-data-structure.py new file mode 100644 index 0000000..a6941c4 --- /dev/null +++ b/challenge-72/design-add-and-search-words-data-structure.py @@ -0,0 +1,36 @@ +class TreeNode: + def __init__(self): + self.children = {} + self.is_end = False +class WordDictionary: + + def __init__(self): + self.trie = TreeNode() + + def addWord(self, word: str) -> None: + node = self.trie + for c in word: + node.children.setdefault(c, TreeNode()) + node = node.children[c] + node.is_end = True + + def search(self, word: str) -> bool: + def dfs(node, i): + if i == len(word): + return node.is_end + + c = word[i] + if c == ".": + return any(dfs(child, i+1) for child in node.children.values()) + if c not in node.children: + return False + return dfs(node.children[c], i+1) + return dfs(self.trie, 0) + + + + +# Your WordDictionary object will be instantiated and called as such: +# obj = WordDictionary() +# obj.addWord(word) +# param_2 = obj.search(word) \ No newline at end of file diff --git a/challenge-73/word-search-ii.py b/challenge-73/word-search-ii.py new file mode 100644 index 0000000..bacc085 --- /dev/null +++ b/challenge-73/word-search-ii.py @@ -0,0 +1,52 @@ +class TreeNode: + def __init__(self): + self.children = {} + self.is_end = False + +class Trie: + def __init__(self): + self.root = TreeNode() + + def insert(self, word): + node = self.root + + for c in word: + node.children.setdefault(c, TreeNode()) + node = node.children[c] + node.is_end = True + +class Solution: + def findWords(self, board: List[List[str]], words: List[str]) -> List[str]: + res = [] + trie = Trie() + node = trie.root + for word in words: + trie.insert(word) + for i in range(len(board)): + for j in range(len(board[0])): + self.dfs(board, node, i, j, "", res) + + return res + + def dfs(self, board, node, i, j, path, res): + if node.is_end: + res.append(path) + node.is_end = False + + if i < 0 or i >= len(board) or j < 0 or j >= len(board[0]): + return + + tmp = board[i][j] + node = node.children.get(tmp) + + if not node: + return + + board[i][j] = "#" + + self.dfs(board, node, i+1, j, path+tmp, res) + self.dfs(board, node, i-1, j, path+tmp, res) + self.dfs(board, node, i, j+1, path+tmp, res) + self.dfs(board, node, i, j-1, path+tmp, res) + + board[i][j] = tmp \ No newline at end of file diff --git a/challenge-74/merge-k-sorted-lists.py b/challenge-74/merge-k-sorted-lists.py new file mode 100644 index 0000000..0c0c97d --- /dev/null +++ b/challenge-74/merge-k-sorted-lists.py @@ -0,0 +1,44 @@ +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution: + def mergeKLists(self, lists: List[Optional[ListNode]]): + if not lists or len(lists) == 0: + return None + + while len(lists) > 1: + temp = [] + + for i in range(0, len(lists), 2): + l1 = lists[i] + l2 = lists[i+1] if i+1 < len(lists) else None + temp.append(self.merge(l1,l2)) + + lists = temp + + return lists[0] + + def merge(self, l1, l2): + node = ListNode() + ans = node + + while l1 and l2: + if l1.val > l2.val: + node.next = l2 + l2 = l2.next + else: + node.next = l1 + l1 = l1.next + node = node.next + + if l1: + node.next = l1 + else: + node.next = l2 + + return ans.next + +# TC : O(N Log K) +# SC : O(K) \ No newline at end of file diff --git a/challenge-75/top-k-frequent-elements.py b/challenge-75/top-k-frequent-elements.py new file mode 100644 index 0000000..aa5aad6 --- /dev/null +++ b/challenge-75/top-k-frequent-elements.py @@ -0,0 +1,20 @@ +class Solution: + def topKFrequent(self, nums: List[int], k: int) -> List[int]: + count = {} + freq = [[] for i in range(len(nums)+1)] + res = [] + + for n in nums: + count[n] = count.get(n, 0)+1 + + for n, c in count.items(): + freq[c].append(n) + + for i in range(len(freq)-1, 0, -1): + for n in freq[i]: + res.append(n) + if len(res) == k: + return res + +# TC : O(N) +# SC : O(N) \ No newline at end of file diff --git a/challenge-76/find-median-from-data-stream.py b/challenge-76/find-median-from-data-stream.py new file mode 100644 index 0000000..9841518 --- /dev/null +++ b/challenge-76/find-median-from-data-stream.py @@ -0,0 +1,30 @@ +from heapq import heappush, heappushpop +class MedianFinder: + + def __init__(self): + self.l_heap = [] + self.r_heap = [] + + def addNum(self, num: int) -> None: + if len(self.l_heap) == len(self.r_heap): + r_num = heappushpop(self.r_heap, num) + heappush(self.l_heap, -r_num) + else: + l_num = heappushpop(self.l_heap, -num) + heappush(self.r_heap, -l_num) + + def findMedian(self) -> float: + if len(self.l_heap) == len(self.r_heap): + return ((-self.l_heap[0]) + self.r_heap[0]) /2 + else: + return -self.l_heap[0] + + + +# Your MedianFinder object will be instantiated and called as such: +# obj = MedianFinder() +# obj.addNum(num) +# param_2 = obj.findMedian() + +# TC : O(LogN) +# SC : O(N) \ No newline at end of file