diff --git a/alien-dictionary/dolphinflow86.py b/alien-dictionary/dolphinflow86.py index 7445860dfb..68088a8843 100644 --- a/alien-dictionary/dolphinflow86.py +++ b/alien-dictionary/dolphinflow86.py @@ -3,11 +3,12 @@ # SC: O(1) - unique letters and adjacency list bounded by 26 characters from collections import deque +from typing import List class Solution: - def alienOrder(self, words) -> str: + def alienOrder(self, words: List[str]) -> str: adj = {char: set() for word in words for char in word} indegree = {char: 0 for word in words for char in word} @@ -41,3 +42,5 @@ def alienOrder(self, words) -> str: return "" return "".join(result) + + alien_order = alienOrder diff --git a/construct-binary-tree-from-preorder-and-inorder-traversal/dolphinflow86.py b/construct-binary-tree-from-preorder-and-inorder-traversal/dolphinflow86.py new file mode 100644 index 0000000000..77dcf2a817 --- /dev/null +++ b/construct-binary-tree-from-preorder-and-inorder-traversal/dolphinflow86.py @@ -0,0 +1,40 @@ +# N is the number of nodes in the binary tree. +# TC: O(N) - building hashmap takes O(N), and each node is visited once in O(1) time +# SC: O(N) - hashmap takes O(N) space, and recursion call stack takes O(H) up to O(N) + +from typing import List, Optional + + +# 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]: + inorder_map = {val: idx for idx, val in enumerate(inorder)} + preorder_idx = 0 + + def build(left: int, right: int) -> Optional[TreeNode]: + nonlocal preorder_idx + + if left > right: + return None + + root_val = preorder[preorder_idx] + root = TreeNode(root_val) + preorder_idx += 1 + + mid = inorder_map[root_val] + + root.left = build(left, mid - 1) + root.right = build(mid + 1, right) + + return root + + return build(0, len(inorder) - 1) diff --git a/longest-palindromic-substring/dolphinflow86.py b/longest-palindromic-substring/dolphinflow86.py new file mode 100644 index 0000000000..d92a71444c --- /dev/null +++ b/longest-palindromic-substring/dolphinflow86.py @@ -0,0 +1,31 @@ +# N is the length of the string s. +# TC: O(N^2) - expanding around each of the 2N - 1 possible centers takes up to O(N) +# SC: O(1) - constant auxiliary space tracking the start index and maximum length + + +class Solution: + + def longestPalindrome(self, s: str) -> str: + if len(s) <= 1: + return s + + start, max_len = 0, 0 + + def expand(left: int, right: int) -> tuple[int, int]: + while left >= 0 and right < len(s) and s[left] == s[right]: + left -= 1 + right += 1 + return left + 1, right - left - 1 + + for i in range(len(s)): + # Odd length palindrome (center is i) + l1, len1 = expand(i, i) + if len1 > max_len: + start, max_len = l1, len1 + + # Even length palindrome (center is between i and i + 1) + l2, len2 = expand(i, i + 1) + if len2 > max_len: + start, max_len = l2, len2 + + return s[start:start + max_len] diff --git a/rotate-image/dolphinflow86.py b/rotate-image/dolphinflow86.py new file mode 100644 index 0000000000..b01b9260ba --- /dev/null +++ b/rotate-image/dolphinflow86.py @@ -0,0 +1,21 @@ +# N is the number of rows and columns in the matrix. +# TC: O(N^2) - reversing rows takes O(N^2) and transposing across diagonal takes O(N^2) +# SC: O(1) - in-place rotation with no extra memory allocation + +from typing import List + + +class Solution: + + def rotate(self, matrix: List[List[int]]) -> None: + """ + Do not return anything, modify matrix in-place instead. + """ + # 1. Flip vertically (reverse rows) + matrix.reverse() + + # 2. Transpose across main diagonal + n = len(matrix) + for i in range(n): + for j in range(i + 1, n): + matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j] diff --git a/subtree-of-another-tree/dolphinflow86.py b/subtree-of-another-tree/dolphinflow86.py new file mode 100644 index 0000000000..4fa0e660df --- /dev/null +++ b/subtree-of-another-tree/dolphinflow86.py @@ -0,0 +1,34 @@ +# M and N are the number of nodes in root and subRoot trees respectively. +# TC: O(M * N) - in the worst case, is_same is checked for every node in root +# SC: O(H) - recursion stack memory bounded by the height of root tree (up to O(M)) + +from typing import Optional + + +# 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: + if not subRoot: + return True + if not root: + return False + + def is_same(s: Optional["TreeNode"], t: Optional["TreeNode"]) -> bool: + if not s and not t: + return True + if not s or not t or s.val != t.val: + return False + return is_same(s.left, t.left) and is_same(s.right, t.right) + + if is_same(root, subRoot): + return True + + return self.isSubtree(root.left, subRoot) or self.isSubtree(root.right, subRoot)