diff --git a/container-with-most-water/dusunax.py b/container-with-most-water/dusunax.py new file mode 100644 index 000000000..d9119e19f --- /dev/null +++ b/container-with-most-water/dusunax.py @@ -0,0 +1,40 @@ +''' +# 11. Container With Most Water + +use two pointers to find the maximum area. + +> **move the shorter line inward:** +> - area is determined by the shorter line. +> - move the shorter line inward => may find a taller line that can increase the area. + +## Time and Space Complexity + +``` +TC: O(n) +SC: O(1) +``` + +### TC is O(n): +- while loop iterates through the height array once. = O(n) + +### SC is O(1): +- using two pointers and max_area variable. = O(1) +''' + +class Solution: + def maxArea(self, height: List[int]) -> int: + left = 0 + right = len(height) - 1 + max_area = 0 + + while left < right: # TC: O(n) + distance = right - left + current_area = min(height[left], height[right]) * distance + max_area = max(current_area, max_area) + + if height[left] < height[right]: + left += 1 + else: + right -= 1 + + return max_area diff --git a/design-add-and-search-words-data-structure/dusunax.py b/design-add-and-search-words-data-structure/dusunax.py new file mode 100644 index 000000000..ec2248d7c --- /dev/null +++ b/design-add-and-search-words-data-structure/dusunax.py @@ -0,0 +1,67 @@ +''' +# 211. Design Add and Search Words Data Structure + +use trie to perform add and search operations on words. +use recursive dfs to search for words with "." wildcards. + +## Time and Space Complexity + +### addWord + +``` +TC: O(n) +SC: O(n) +``` + +### TC is O(n): +- iterating through each character of the word. = O(n) + +### SC is O(n): +- storing the word in the trie. = O(n) + +### search + +``` +TC: O(n) +SC: O(n) +``` + +### TC is O(n): +- dfs iterates through each character of the word. = O(n) +- if char is "."(wildcard) dfs iterates through all children of the current node. = O(n) + +> recursion for the wildcard could involve exploring several paths. +> but time complexity is bounded by the length of the word, so it's still O(n). + +### SC is O(n): +- length of the word as recursive call stack. = O(n) +''' +class WordDictionary: + def __init__(self): + self.trie = {} + + def addWord(self, word: str) -> None: + node = self.trie + for char in word: # TC: O(n) + if char not in node: + node[char] = {} + node = node[char] + node["$"] = True + + def search(self, word: str) -> bool: + def dfs(node, i) -> bool: + if not isinstance(node, dict): + return False + if i == len(word): + return "$" in node if isinstance(node, dict) else False + char = word[i] + + if char == ".": + for child in node.values(): + if dfs(child, i + 1): + return True + return False + else: + return dfs(node[char], i+1) if char in node else False + + return dfs(self.trie, 0) diff --git a/longest-increasing-subsequence/dusunax.py b/longest-increasing-subsequence/dusunax.py new file mode 100644 index 000000000..992157ea3 --- /dev/null +++ b/longest-increasing-subsequence/dusunax.py @@ -0,0 +1,58 @@ +''' +# 300. Longest Increasing Subsequence + +use the sub list to store current LIS. +iterate nums's elements and find the position of the current number in the subsequence. (using a binary search helper function) +after the iteration finishes, return the length of the subsequence. + +> **helper function explanation:** +> ```py +> position = bisectLeft(sub, num) +> ``` +> bisectLeft is doing binary search that finds the leftmost position in a sorted list. +>if the position is the end of the subsequence, append the current number to the subsequence. +>if the position is not the end of the subsequence, replace the number at the position with the current number. + +> **python's bisect module:** +> https://docs.python.org/3.10/library/bisect.html + +## Time and Space Complexity + +``` +TC: O(n log n) +SC: O(n) +``` + +#### TC is O(n log n): +- iterating through the nums list to find the position of the current number. = O(n) +- using a binary search helper function to find the position of the current number. = O(log n) + +#### SC is O(n): +- using a list to store the subsequence. = O(n) in the worst case +''' +class Solution: + def lengthOfLIS(self, nums: List[int]) -> int: + sub = [] # SC: O(n) + + for num in nums: # TC: O(n) + pos = self.bisectLeft(sub, num) # bisect.bisect_left(sub, num) = TC: O(log n) + if pos == len(sub): + sub.append(num) + else: + sub[pos] = num + + return len(sub) + + def bisectLeft(self, list, target) -> int: + low = 0 + high = len(list) - 1 + + while low <= high : + mid = int(low + (high - low) / 2) + + if list[mid] < target: + low = mid + 1 + else: + high = mid - 1 + + return low diff --git a/spiral-matrix/dusunax.py b/spiral-matrix/dusunax.py new file mode 100644 index 000000000..d58edafc2 --- /dev/null +++ b/spiral-matrix/dusunax.py @@ -0,0 +1,52 @@ +''' +# 54. Spiral Matrix + +to traverse the matrix in a spiral order: +1. do boundary-tracking +2. iterate in layers + - move right, move down, move left, move up + - shrink the boundaries +4. return the result + +# Time and Space Complexity + +``` +TC: O(m * n) +SC: O(1) +``` + +#### TC is O(m * n): +move through the 2D matrix just once. = O(m * n) + +#### SC is O(1): +result list is excluded from auxiliary space, so it's = O(1) +''' + +class Solution: + def spiralOrder(self, matrix: List[List[int]]) -> List[int]: + top = 0 + left = 0 + bottom = len(matrix) - 1 + right = len(matrix[0]) - 1 + result = [] # SC: O(1) + + while top <= bottom and left <= right: + for i in range(left, right + 1): + result.append(matrix[top][i]) + top += 1 + + for i in range(top, bottom + 1): + result.append(matrix[i][right]) + right -= 1 + + if top <= bottom: + for i in range(right, left - 1, -1): + result.append(matrix[bottom][i]) + bottom -= 1 + + if left <= right: + for i in range(bottom, top - 1, -1): + result.append(matrix[i][left]) + left += 1 + + return result diff --git a/valid-parentheses/dusunax.py b/valid-parentheses/dusunax.py new file mode 100644 index 000000000..f7fbee60f --- /dev/null +++ b/valid-parentheses/dusunax.py @@ -0,0 +1,41 @@ +''' +# 20. Valid Parentheses + +use stack data structure to perform as a LIFO + +## Time and Space Complexity + +``` +TC: O(n) +SC: O(n) +``` + +#### TC is O(n): +- iterating through the string just once to check if the parentheses are valid. = O(n) + +#### SC is O(n): +- using a stack to store the parentheses. = the worst case is O(n) +- using a map to store the parentheses. = O(1) + +> for space complexity, fixed space is O(1). +> 👉 parentheses_map is fixed and its size doesn't grow with the input size. +> 👉 if the map has much larger size? the space complexity is still O(1). +''' + +class Solution: + def isValid(self, s: str) -> bool: + stack = [] # SC: O(n) + parentheses_map = { # SC: O(1) + "(": ")", + "{": "}", + "[": "]" + } + + for char in s: # TC: O(n) + if char in parentheses_map: + stack.append(char) + else: + if len(stack) == 0 or parentheses_map[stack.pop()] != char: + return False + + return not stack