diff --git a/container-with-most-water/alphaorderly.py b/container-with-most-water/alphaorderly.py new file mode 100644 index 0000000000..978b083aaf --- /dev/null +++ b/container-with-most-water/alphaorderly.py @@ -0,0 +1,33 @@ +""" +Time Complexity: O(n) + - n = number of elements in height + - Each index is visited at most once by either the left or right pointer. + +Space Complexity: O(1) + - Only a small constant number of variables are used (left, right, ans). + +Approach: + - Initialize two pointers at the beginning (left) and end (right) of the array. + - At each step, compute the area formed by the lines at left and right. + - Update the maximum area found so far. + - Move the pointer pointing to the shorter line inward (increase left or decrease right). + - Ensure to move shorter line inward to potentially find a taller line that could increase the area. + - Because amount of water is determined by the shorter line. + - Continue until the two pointers meet. + - Return the maximum area found. +""" +class Solution: + def maxArea(self, height: List[int]) -> int: + N = len(height) + left, right = 0, N - 1 + ans = 0 + + while left < right: + ans = max(ans, min(height[left], height[right]) * (right - left)) + + if height[left] < height[right]: + left += 1 + else: + right -= 1 + + return ans diff --git a/design-add-and-search-words-data-structure/alphaorderly.py b/design-add-and-search-words-data-structure/alphaorderly.py new file mode 100644 index 0000000000..0571eaa874 --- /dev/null +++ b/design-add-and-search-words-data-structure/alphaorderly.py @@ -0,0 +1,84 @@ +""" +Trie-based add and search with wildcard support. + +### BFS approach ### + +Time Complexity: + - addWord: O(L), where L is the length of the inserted word. + - search: O(N), where N is the length of the search word; search with '.' wildcard may lead to O(B^N) in the worst case, + where B is average branching factor. For ordinary searches (no wildcards), still O(N). + +Space Complexity: O(T) + - T = total number of characters in all inserted words, due to nodes in the trie. +""" + +class WordDictionary: + + def __init__(self): + self.children = dict() + self.end = False + + def addWord(self, word: str) -> None: + node = self + for ch in word: + if ch not in node.children: + node.children[ch] = WordDictionary() + node = node.children[ch] + node.end = True + + def search(self, word: str) -> bool: + search = deque([self]) + for ch in word: + S = len(search) + for _ in range(S): + node = search.popleft() + if ch == '.': + for child in node.children.values(): + search.append(child) + elif ch in node.children: + search.append(node.children[ch]) + + return any(node.end for node in search) + +""" +Trie-based add and recursive search with wildcard support. + +### DFS approach ### + +Time Complexity: + - addWord: O(L), where L is the length of the inserted word. + - search: Worst case O(B^N), where N is the length of the search word and B is average branching factor if all + positions are wildcards. Otherwise O(N) for ordinary search. + +Space Complexity: O(T) + - T = total number of characters in all inserted words (trie size), plus call stack space O(N) during search. +""" + +class WordDictionary: + + def __init__(self): + self.children = dict() + self.end = False + + def addWord(self, word: str) -> None: + node = self + for ch in word: + if ch not in node.children: + node.children[ch] = WordDictionary() + node = node.children[ch] + node.end = True + + def search(self, word: str) -> bool: + def dfs(node: WordDictionary, index: int) -> bool: + if index == len(word): + return node.end + ch = word[index] + if ch == ".": + for child in node.children.values(): + if dfs(child, index + 1): + return True + elif ch in node.children: + return dfs(node.children[ch], index + 1) + return False + + return dfs(self, 0) diff --git a/longest-increasing-subsequence/alphaorderly.py b/longest-increasing-subsequence/alphaorderly.py new file mode 100644 index 0000000000..e2aeaa6168 --- /dev/null +++ b/longest-increasing-subsequence/alphaorderly.py @@ -0,0 +1,23 @@ +""" +Time Complexity: O(n log n) +Space Complexity: O(n) + +### Binary search approach ### + +For each number in nums: + - Find the insertion position for num in arr to maintain sorted order (binary search). + - If num is greater than all elements in arr, append it (extend the LIS). + - Otherwise, replace the element at position with num to keep tails as small as possible. +""" +class Solution: + def lengthOfLIS(self, nums: List[int]) -> int: + arr = [] + + for num in nums: + position = bisect_left(arr, num) + if position == len(arr): + arr.append(num) + else: + arr[position] = num + + return len(arr) diff --git a/spiral-matrix/alphaorderly.py b/spiral-matrix/alphaorderly.py new file mode 100644 index 0000000000..089cea7193 --- /dev/null +++ b/spiral-matrix/alphaorderly.py @@ -0,0 +1,38 @@ +""" +Spiral traversal of a matrix: visit all elements in "spiral order" (clockwise from top-left). + +Time Complexity: O(N), where N is the total number of elements in matrix. + - Each element is visited once. + +Space Complexity: O(N) + - The output array includes all N elements. + - The input matrix is modified in-place to mark visited cells. +""" +class Solution: + def spiralOrder(self, matrix: List[List[int]]) -> List[int]: + ROW = len(matrix) + COL = len(matrix[0]) + TARGET = ROW * COL + DIR = [[0, 1], [1, 0], [0, -1], [-1, 0]] + CHECK = -1000 + + ans = [] + + def bound(r: int, c: int) -> bool: + return 0 <= r < ROW and 0 <= c < COL + + r = c = d = 0 + + for _ in range(TARGET): + ans.append(matrix[r][c]) + matrix[r][c] = CHECK + + tr = r + DIR[d][0] + tc = c + DIR[d][1] + if not bound(tr, tc) or matrix[tr][tc] == CHECK: + d = (d + 1) % 4 + r += DIR[d][0] + c += DIR[d][1] + + + return ans diff --git a/valid-parentheses/alphaorderly.py b/valid-parentheses/alphaorderly.py new file mode 100644 index 0000000000..18c7ef523e --- /dev/null +++ b/valid-parentheses/alphaorderly.py @@ -0,0 +1,30 @@ +""" +Time Complexity: O(n) + - Each character in the input string s is visited exactly once in a single left-to-right scan. + - Each push or pop operation on the stack corresponds to a character, for at most O(n) stack operations. + +Space Complexity: O(n) + - In the worst case (e.g., all opening brackets), the stack may contain up to n elements. + - The auxiliary data structure (`pairs`) uses constant space, as there are only three types of parentheses. + +Approach: + The algorithm uses a stack to simulate balancing of brackets. + - For every opening bracket encountered, push it onto the stack. + - For every closing bracket, check if the top of the stack holds its matching opening bracket. + - If not, or if the stack is empty, the string is invalid. + - At the end, if the stack is empty, all open brackets were matched and closed properly. +""" +class Solution: + def isValid(self, s: str) -> bool: + pairs = {"(": ")", "{": "}", "[": "]"} + stack = [] + + for ch in s: + if ch in pairs: + stack.append(ch) + elif not stack or pairs[stack[-1]] != ch: + return False + else: + stack.pop() + + return not stack