diff --git a/coin-change/dusunax.py b/coin-change/dusunax.py new file mode 100644 index 000000000..f6b6fd0d8 --- /dev/null +++ b/coin-change/dusunax.py @@ -0,0 +1,49 @@ +''' +# 322. Coin Change + +use a queue for BFS & iterate through the coins and check the amount is down to 0. +use a set to the visited check. + +## Time and Space Complexity + +``` +TC: O(n * Amount) +SC: O(Amount) +``` + +#### TC is O(n * Amount): +- sorting the coins = O(n log n) +- reversing the coins = O(n) +- iterating through the queue = O(Amount) +- iterating through the coins and check the remaining amount is down to 0 = O(n) + +#### SC is O(Amount): +- using a queue to store (the remaining amount, the count of coins) tuple = O(Amount) +- using a set to store the visited check = O(Amount) +''' +class Solution: + def coinChange(self, coins: List[int], amount: int) -> int: + if amount == 0: + return 0 + if len(coins) == 1 and coins[0] == amount: + return 1 + + coins.sort() # TC: O(n log n) + coins.reverse() # TC: O(n) + + queue = deque([(amount, 0)]) # SC: O(Amount) + visited = set() # SC: O(Amount) + + while queue: # TC: O(Amount) + remain, count = queue.popleft() + + for coin in coins: # TC: O(n) + next_remain = remain - coin + + if next_remain == 0: + return count + 1 + if next_remain > 0 and next_remain not in visited: + queue.append((next_remain, count + 1)) + visited.add(next_remain) + + return -1 diff --git a/merge-two-sorted-lists/dusunax.py b/merge-two-sorted-lists/dusunax.py new file mode 100644 index 000000000..11bc24dc4 --- /dev/null +++ b/merge-two-sorted-lists/dusunax.py @@ -0,0 +1,77 @@ +''' +# 21. Merge Two Sorted Lists + +A. iterative approach: use a two pointers to merge the two lists. +B. recursive approach: use recursion to merge the two lists. + + +## Time and Space Complexity + +### A. Iterative Approach + +``` +TC: O(n + m) +SC: O(1) +``` + +#### TC is O(n + m): +- iterating through the two lists just once for merge two sorted lists. = O(n + m) + +#### SC is O(1): +- temp node is used to store the result. = O(1) + +### B. Recursive Approach + +``` +TC: O(n + m) +SC: O(n + m) +``` + +#### TC is O(n + m): +- iterating through the two lists just once for merge two sorted lists. = O(n + m) + +#### SC is O(n + m): +- because of the recursive call stack. = O(n + m) +''' +class Solution: + ''' + A. Iterative Approach + - use a temp node to store the result. + - use a current node to iterate through the two lists. + ''' + def mergeTwoListsIterative(self, list1: Optional[ListNode], list2: Optional[ListNode]) -> Optional[ListNode]: + temp = ListNode(-1) + current = temp + + while list1 is not None and list2 is not None: + if list1.val < list2.val: + current.next = list1 + list1 = list1.next + else: + current.next = list2 + list2 = list2.next + current = current.next + + if list1 is not None: + current.next = list1 + elif list2 is not None: + current.next = list2 + + return temp.next + + ''' + B. Recursive Approach + - use recursion to merge the two lists. + ''' + def mergeTwoListsRecursive(self, list1: Optional[ListNode], list2: Optional[ListNode]) -> Optional[ListNode]: + if list1 is None: + return list2 + elif list2 is None: + return list1 + + if list1.val < list2.val: + list1.next = self.mergeTwoLists(list1.next, list2) + return list1 + else: + list2.next = self.mergeTwoLists(list1, list2.next) + return list2 diff --git a/missing-number/dusunax.py b/missing-number/dusunax.py new file mode 100644 index 000000000..6d4be40a8 --- /dev/null +++ b/missing-number/dusunax.py @@ -0,0 +1,63 @@ +''' +# 268. Missing Number + +A. iterative approach: sort the array and find the missing number. +B. XOR approach: use XOR to find the missing number. + - a ^ a = 0, a ^ 0 = a + +## Time and Space Complexity + +### A. Iterative Approach + +``` +TC: O(n log n) +SC: O(1) +``` + +#### TC is O(n): +- sorting the array. = O(n log n) +- iterating through the array just once to find the missing number. = O(n) + +#### SC is O(1): +- no extra space is used. = O(1) + +### B. XOR Approach + +``` +TC: O(n) +SC: O(1) +``` + +#### TC is O(n): +- iterating through the array just once to find the missing number. = O(n) + +#### SC is O(1): +- no extra space is used. = O(1) + +''' +class Solution: + ''' + A. Iterative Approach + ''' + def missingNumberIterative(self, nums: List[int]) -> int: + nums.sort() + n = len(nums) + + for i in range(n): + if nums[i] != i: + return i + return n + + ''' + B. XOR Approach + ''' + def missingNumberXOR(self, nums: List[int]) -> int: + n = len(nums) + xor_nums = 0 + + for i in range(n + 1): + if i < n: + xor_nums ^= nums[i] + xor_nums ^= i + + return xor_nums diff --git a/palindromic-substrings/dusunax.py b/palindromic-substrings/dusunax.py new file mode 100644 index 000000000..384960667 --- /dev/null +++ b/palindromic-substrings/dusunax.py @@ -0,0 +1,78 @@ +''' +# 647. Palindromic Substrings + +A. use dynamic programming table to store the palindrome status. +B. use two pointers to expand around the center. + +## Time and Space Complexity + +### A. Dynamic Programming Table +``` +TC: O(n^2) +SC: O(n^2) +``` + +#### TC is O(n^2): +- filling DP table by iterating through all substrings. +- each cell (i, j) checks if a substring is a palindrome & counting the cases = O(n^2) + +#### SC is O(n^2): +- storing the n x n dp table. = O(n^2) + +### B. Expand Around Center +``` +TC: O(n^2) +SC: O(1) +``` + +#### TC is O(n^2): +- for each char, expand outwards to check for palindromes. = O(n^2) + +#### SC is O(1): +- no additional data structures are used. `count` is a single integer. = O(1) +''' +class Solution: + def countSubstringsDPTable(self, s: str) -> int: + ''' + A. Dynamic Programming Table + ''' + n = len(s) + dp = [[False] * n for _ in range(n)] # List comprehension. = SC: O(n^2) + count = 0 + + for i in range(n): # TC: O(n) + dp[i][i] = True + count += 1 + + for i in range(n - 1): + if s[i] == s[i + 1]: + dp[i][i + 1] = True + count += 1 + + for s_len in range(3, n + 1): # TC: O(n) + for i in range(n - s_len + 1): # TC: O(n) + j = i + s_len - 1 + + if s[i] == s[j] and dp[i + 1][j - 1]: + dp[i][j] = True + count += 1 + + return count + def countSubstrings(self, s: str) -> int: + ''' + B. Expand Around Center + ''' + count = 0 + + def expand(left, right): + nonlocal count + while left >= 0 and right < len(s) and s[left] == s[right]: # TC: O(n) + count += 1 + left -= 1 + right += 1 + + for i in range(len(s)): # TC: O(n) + expand(i, i) + expand(i, i + 1) + + return count diff --git a/word-search/dusunax.py b/word-search/dusunax.py new file mode 100644 index 000000000..fb3e1f855 --- /dev/null +++ b/word-search/dusunax.py @@ -0,0 +1,52 @@ +''' +# 79. Word Search + +use backtracking(DFS) to search for the word in the board. + +## Time and Space Complexity + +``` +TC: O(n * m * 4^L) +SC: O(L) +``` + +#### TC is O(n * m * 4^L): +- n is the number of rows in the board. +- m is the number of columns in the board. +- L is the length of the word. + - 4^L is the number of directions we can go at each step. (explores 4 branches recursively) + +#### SC is O(L): +- modifying the board in-place to mark visited cells. = O(L) +''' +class Solution: + def exist(self, board: List[List[str]], word: str) -> bool: + rows = len(board) + cols = len(board[0]) + + def backtracking(i, j, word_index): # TC: O(4^L), SC: O(L) + if word_index == len(word): + return True + + if i < 0 or i >= rows or j < 0 or j >= cols or board[i][j] != word[word_index]: + return False + + temp = board[i][j] + board[i][j] = "." + + found = ( + backtracking(i + 1, j, word_index + 1) or + backtracking(i - 1, j, word_index + 1) or + backtracking(i, j + 1, word_index + 1) or + backtracking(i, j - 1, word_index + 1) + ) + board[i][j] = temp + + return found + + for row in range(rows): # TC: O(n * m) + for col in range(cols): + if backtracking(row, col, 0): + return True + + return False