├── .gitignore ├── 1 - Two Sum.py ├── 112 - Path Sum I.py ├── 118 - Pascal's Triangle I.py ├── 13 - Roman to Integer.py ├── 136 - Single Number.py ├── 14 - Longest Common Prefix.py ├── 144 - Binary Tree Preorder Traversal.md ├── 145 - Binary Tree Postorder Traversal.md ├── 15 - 3 Sum.md ├── 1512 - Number of Good Pairs.py ├── 155 - Min Stack.py ├── 19 - Remove Nth Node From List.md ├── 203 - Remove Linked List Elements.md ├── 206 - Reverse Linked List.py ├── 21 - Merge Two Sorted Lists.md ├── 21.py ├── 217 - Contains Duplicates.md ├── 226.py ├── 237 - Delete Node in a Linked List.py ├── 26 - Remove duplicates from sorted array.md ├── 278 - First Bad Version.md ├── 283 - Move Zeroes.py ├── 3 - Longest Substring Without Repeating Characters.md ├── 3.py ├── 35 - Search Insert Position.md ├── 567 - Permutation in String.py ├── 7 - Reverse Integer.py ├── 704 - Binary Search.md ├── 83 - Remove Duplicates from Sorted List.py ├── 9 - Palindrome Number.py ├── 94 - Binary Tree Inorder Traversal.md ├── 977 - Squares Of A Sorted Array.md ├── 977.py ├── README.md ├── coding-challenge-august ├── week 1 │ ├── Add and Search Word.py │ ├── Design Hashset.py │ ├── Detect Capital.py │ ├── Find All Duplicates.py │ ├── Power of Four.py │ ├── Valid Palindrome.py │ ├── Vertical Order Traversal of a Binary Tree.py │ └── __init__.py └── week 2 │ ├── Excel Sheet Column Number.py │ ├── Pascal's Triangle II.py │ ├── Path Sum III.py │ └── __init__.py ├── images ├── 19-1.png ├── 19-2.png ├── 19-example.png ├── 203-1.png ├── 203-2.png ├── 21-1.png ├── 21-2.png ├── 26.png ├── 278.png ├── 3-1.png ├── 3-2.png ├── 35-1.png ├── 35-2.png ├── 94-1.png ├── 94-2.png ├── Screen_Shot_2022-02-12_at_5.36.32_PM.png └── Screen_Shot_2022-02-12_at_5.36.49_PM.png └── requirements.txt /.gitignore: -------------------------------------------------------------------------------- 1 | env/ 2 | env 3 | .env 4 | 5 | .idea 6 | .idea/ 7 | 8 | .vscode 9 | vscode -------------------------------------------------------------------------------- /1 - Two Sum.py: -------------------------------------------------------------------------------- 1 | # 1. Two Sum 2 | # Easy 3 | # Given an array of integers, return indices of the two numbers such that they 4 | # add up to a specific target. You may assume that each input would have 5 | # exactly one solution, and you may not use the same element twice. 6 | 7 | # Example: 8 | # Given nums = [2, 7, 11, 15], target = 9, 9 | # Because nums[0] + nums[1] = 2 + 7 = 9, 10 | # return [0, 1]. 11 | from typing import List 12 | 13 | 14 | class Solution: 15 | def twoSum(self, nums: List[int], target: int) -> List[int]: 16 | my_dict = {} 17 | for index, num in enumerate(nums): 18 | diff = target-num 19 | if diff not in my_dict: 20 | my_dict[num] = index 21 | else: 22 | indeces = [my_dict[diff], index] 23 | 24 | return indeces 25 | -------------------------------------------------------------------------------- /112 - Path Sum I.py: -------------------------------------------------------------------------------- 1 | # Definition for a binary tree node. 2 | # class TreeNode: 3 | # def __init__(self, val=0, left=None, right=None): 4 | # self.val = val 5 | # self.left = left 6 | # self.right = right 7 | 8 | 9 | class Solution: 10 | def hasPathSum(self, root: TreeNode, sum: int) -> bool: 11 | result = [] 12 | self.depthFirstSearch(root, sum, result) 13 | return any(result) # Returns true if True in iterable 14 | 15 | def depthFirstSearch(self, root, sum, result): 16 | # pre-order DFS recursive traversal 17 | 18 | if not root: 19 | return False 20 | 21 | # Traverse until no child nodes; not root.L && not root.R 22 | if not root.left and not root.right: 23 | if root.val == sum: 24 | result.append(True) 25 | 26 | if root.left: 27 | self.depthFirstSearch(root.left, sum-root.val, result) 28 | 29 | if root.right: 30 | self.depthFirstSearch(root.right, sum-root.val, result) 31 | -------------------------------------------------------------------------------- /118 - Pascal's Triangle I.py: -------------------------------------------------------------------------------- 1 | # 118. Pascal's Triangle 2 | # Easy 3 | # Given a non-negative integer numRows, generate the first numRows of Pascal's triangle. 4 | # In Pascal's triangle, each number is the sum of the two numbers directly above it. 5 | 6 | # Example: 7 | # Input: 5 8 | # Output: 9 | # [ 10 | # [1], 11 | # [1,1], 12 | # [1,2,1], 13 | # [1,3,3,1], 14 | # [1,4,6,4,1] 15 | # ] 16 | from typing import List 17 | 18 | 19 | class Solution: 20 | def generate(self, numRows: int) -> List[List[int]]: 21 | if numRows == 1 or numRows < 0: 22 | return [[1]] 23 | 24 | elif numRows == 2: 25 | return [[1], [1, 1]] 26 | 27 | else: 28 | triangle = [[1], [1, 1]] 29 | for i in range(1, numRows-1): 30 | current_row = [1] 31 | j = 0 32 | while j < i: 33 | current_row.append(triangle[i][j] + triangle[i][j+1]) 34 | j += 1 35 | 36 | current_row.append(1) 37 | triangle.append(current_row) 38 | 39 | return triangle[numRows - 1] 40 | -------------------------------------------------------------------------------- /13 - Roman to Integer.py: -------------------------------------------------------------------------------- 1 | # Roman numerals are represented by seven different symbols: I, V, X, L, C, D and M. 2 | 3 | # Symbol Value 4 | # I 1 5 | # V 5 6 | # X 10 7 | # L 50 8 | # C 100 9 | # D 500 10 | # M 1000 11 | 12 | # For example, two is written as II in Roman numeral, just two one's added together. 13 | # Twelve is written as, XII, which is simply X + II. 14 | 15 | # The number twenty seven is written as XXVII, which is XX + V + II. 16 | # Roman numerals are usually written largest to smallest from left to right. 17 | # However, the numeral for four is not IIII. Instead, the number four is written as IV. 18 | # Because the one is before the five we subtract it making four. The same principle applies to the number nine, which is written as IX. 19 | 20 | # There are six instances where subtraction is used: 21 | # I can be placed before V (5) and X (10) to make 4 and 9. 22 | # X can be placed before L (50) and C (100) to make 40 and 90. 23 | # C can be placed before D (500) and M (1000) to make 400 and 900. 24 | # Given a roman numeral, convert it to an integer. Input is guaranteed to be within the range from 1 to 3999. 25 | 26 | # Example 1: 27 | # Input: "III" 28 | # Output: 3 29 | 30 | # Example 2: 31 | # Input: "IV" 32 | # Output: 4 33 | 34 | # Example 3: 35 | # Input: "IX" 36 | # Output: 9 37 | 38 | # Example 4: 39 | # Input: "LVIII" 40 | # Output: 58 41 | # Explanation: L = 50, V= 5, III = 3. 42 | 43 | # Example 5: 44 | # Input: "MCMXCIV" 45 | # Output: 1994 46 | # Explanation: M = 1000, CM = 900, XC = 90 and IV = 4. 47 | 48 | class Solution: 49 | def romanToInt(self, s: str) -> int: 50 | edge = { 51 | 'IV': 4, 52 | 'IX': 9, 53 | 'XL': 40, 54 | 'XC': 90, 55 | 'CD': 400, 56 | 'CM': 900, 57 | } 58 | 59 | if s in edge.keys(): 60 | return edge[s] 61 | else: 62 | total = 0 63 | for key in edge.keys(): 64 | if key in s: 65 | s = s.replace(key, '') 66 | total += edge[key] 67 | romans = { 68 | "I": 1, 69 | "V": 5, 70 | "X": 10, 71 | "L": 50, 72 | "C": 100, 73 | "D": 500, 74 | "M": 1000, 75 | } 76 | 77 | for letter in s: 78 | total += romans[letter] 79 | return total 80 | 81 | 82 | # Runtime: 44 ms, faster than 87.37% of Python3 online submissions for Roman to Integer. 83 | # Memory Usage: 13.8 MB, less than 69.07% of Python3 online submissions for Roman to Integer. -------------------------------------------------------------------------------- /136 - Single Number.py: -------------------------------------------------------------------------------- 1 | # 136. Single Number 2 | # Easy 3 | # Given a non-empty array of integers, every element appears twice except for one. Find that single one. 4 | 5 | # Note: 6 | # Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory? 7 | 8 | # Example 1: 9 | # Input: [2,2,1] 10 | # Output: 1 11 | 12 | # Example 2: 13 | # Input: [4,1,2,1,2] 14 | # Output: 4 15 | 16 | from typing import List 17 | 18 | 19 | class Solution: 20 | def singleNumber(self, nums: List[int]) -> int: 21 | uniques = [] 22 | for num in nums: 23 | if num in uniques: 24 | uniques.remove(num) 25 | else: 26 | uniques.append(num) 27 | 28 | return uniques[0] 29 | -------------------------------------------------------------------------------- /14 - Longest Common Prefix.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def longestCommonPrefix(self, strs: List[str]) -> str: 3 | # traverse smallest word in list 4 | # traverse all words in list 5 | # if letter in word does not equal the current letter of smallest word 6 | # return current word sliced up to the current index of smallest word 7 | if not strs: 8 | return '' 9 | 10 | smallest = min(strs, key=len) 11 | for index, char in enumerate(smallest): 12 | for word in strs: 13 | if word[index] != char: 14 | return smallest[:index] 15 | 16 | # finally return smallest 17 | return smallest 18 | -------------------------------------------------------------------------------- /144 - Binary Tree Preorder Traversal.md: -------------------------------------------------------------------------------- 1 | # 144 - Binary Tree Preorder Traversal 2 | 3 | Difficulty: easy 4 | Done: Yes 5 | Last edited: March 13, 2022 10:59 PM 6 | Link: https://leetcode.com/problems/binary-tree-preorder-traversal/ 7 | Topic: recursion, tree 8 | 9 | ## Problem 10 | 11 | --- 12 | 13 | Given the `root` of a binary tree, return *the preorder traversal of its nodes' values*. 14 | 15 | ``` 16 | Input: root = [1,null,2,3] 17 | Output: [1,2,3] 18 | ``` 19 | 20 | ## Solution 21 | 22 | --- 23 | 24 | Pre-order traversal requires order of parent -> left child -> right child. Can do so recursively, and return empty array if input is none 25 | 26 | ## Code 27 | 28 | --- 29 | 30 | ```python 31 | # Definition for a binary tree node. 32 | # class TreeNode: 33 | # def __init__(self, val=0, left=None, right=None): 34 | # self.val = val 35 | # self.left = left 36 | # self.right = right 37 | class Solution: 38 | def preorderTraversal(self, root: Optional[TreeNode]) -> List[int]: 39 | 40 | # if we have no nodes in input return empty list 41 | if not root: 42 | return [] 43 | 44 | # pre-order traversal requires order of parent -> left child -> right child 45 | # can do so recursively 46 | 47 | return [root.val] + self.preorderTraversal(root.left) + self.preorderTraversal(root.right) 48 | ``` 49 | 50 | ## Time Complexity 51 | 52 | --- 53 | 54 | The time complexity is O(n)*O*(*n*) because the recursive function is $T(n)=2⋅T(n/2)+1T(n)=2⋅T(n/2)+1$. -------------------------------------------------------------------------------- /145 - Binary Tree Postorder Traversal.md: -------------------------------------------------------------------------------- 1 | # 145 - Binary Tree Postorder Traversal 2 | 3 | Difficulty: easy 4 | Done: Yes 5 | Last edited: March 13, 2022 10:59 PM 6 | Link: https://leetcode.com/problems/binary-tree-postorder-traversal/ 7 | Topic: recursion, tree 8 | 9 | ## Problem 10 | 11 | --- 12 | 13 | Given the `root` of a binary tree, return *the preorder traversal of its nodes' values*. 14 | 15 | ``` 16 | Input: root = [1,null,2,3] 17 | Output: [3,2,1] 18 | ``` 19 | 20 | ## Solution 21 | 22 | --- 23 | 24 | post order goes as left child -> right child -> root 25 | 26 | ## Code 27 | 28 | --- 29 | 30 | ```python 31 | # Definition for a binary tree node. 32 | # class TreeNode: 33 | # def __init__(self, val=0, left=None, right=None): 34 | # self.val = val 35 | # self.left = left 36 | # self.right = right 37 | class Solution: 38 | def postorderTraversal(self, root: Optional[TreeNode]) -> List[int]: 39 | return self.postorderTraversal(root.left) + self.postorderTraversal(root.right) + [root.val] if root is not None else [] 40 | ``` 41 | 42 | ## Time Complexity 43 | 44 | --- 45 | 46 | The time complexity is O(n)*O*(*n*) because the recursive function is $T(n)=2⋅T(n/2)+1T(n)=2⋅T(n/2)+1$. -------------------------------------------------------------------------------- /15 - 3 Sum.md: -------------------------------------------------------------------------------- 1 | # 15 - 3 Sum 2 | 3 | Difficulty: medium 4 | Done: No 5 | Last edited: February 22, 2022 1:23 AM 6 | Topic: array, sorting, two pointers 7 | 8 | ## Problem 9 | 10 | Given an integer array nums, return all the triplets `[nums[i], nums[j], nums[k]]` such that `i != j`, `i != k`, and `j != k`, and `nums[i] + nums[j] + nums[k] == 0`. 11 | 12 | Notice that the solution set must not contain duplicate triplets. 13 | 14 | ## Solution 15 | 16 | Problem is framed like the popular two sum where we find 2 values $(x, y)$ which add up to given target, which can be solved by finding if difference between target and value $(target - x)$ exists in array. 17 | 18 | However, here we are required to work with 3 values $(x, y, z)$ and **find all triplets where sum of values is zero** $x+y+z=0$. This must be done without repeating the elements, though input array can contain duplicates. 19 | 20 | This approach will only work with sorted array 21 | 22 | ### Pseudo 23 | 24 | 1. Sort array 25 | 2. Iterate through elements, setting current element as the pivot $x$. 26 | 1. if current value (lowest) is greater than zero, then this would indicate there are only non-negative elements, which cannot sum to 0. 27 | 2. if current value is same as preceding (duplicate), then skip. 28 | 3. Proceed to step 3 29 | 3. Use two pointer approach to compare values, starting with *left_ptr* at position $x+1$, and *right_ptr* at the end of the array or $len(nums)$-1. We want to find all pairs whose sum is equal to 0, or $(x+y+z)=0$. 30 | 31 | We will do so by creating separate function which essentially performs two-sum. Loop while *left_ptr* is smaller than *right_ptr* 32 | 33 | 1. If $sum(x, y, z)$ is greater than 0, we will increment *left_ptr* 34 | 2. Elif $sum(x,y, z)$ is less than 0, we will decrement *right_pt* 35 | 3. if sum is zero, meaning **triplet found,** add to results list. Increment left and decrement right. Increment left while while $left = left+1$, to skip duplicates. 36 | 37 | ## Whiteboard 38 | 39 | [http://excalidraw.com](http://excalidraw.com) 40 | 41 | ## Code 42 | 43 | ```python 44 | class Solution: 45 | def threeSum(self, nums: List[int]) -> List[List[int]]: 46 | triplets = [] 47 | nums.sort() 48 | 49 | for i in range(len(nums)): 50 | # check if all elements are non-negative 51 | if nums[i] > 0: 52 | break 53 | 54 | # skip duplicates 55 | # call two_sum function to find triplets with i as target 56 | if nums[i-1] != nums[i] or i == 0: 57 | self.two_sum(i, nums, triplets) 58 | 59 | return triplets 60 | 61 | 62 | def two_sum(self, i: int, nums: List[int], triplets: List[List[int]]): 63 | # define left & right pointers 64 | # loop while left & right pointers aren't at same position l < r 65 | 66 | left = i + 1 67 | right = len(nums) - 1 68 | 69 | while left < right: 70 | total = nums[i] + nums[left] + nums[right] 71 | 72 | 73 | #if sum > 0, increment left 74 | if total < 0: 75 | left += 1 76 | 77 | # if sum < 0, decrement right 78 | elif total > 0: 79 | right -= 1 80 | 81 | else: 82 | # if sum is 0, add to triplets list 83 | triplets.append([nums[i], nums[left], nums[right]]) 84 | left += 1 85 | right -= 1 86 | 87 | while left < right and nums[left] == nums[left-1]: 88 | # skip duplicates 89 | left += 1 90 | ``` -------------------------------------------------------------------------------- /1512 - Number of Good Pairs.py: -------------------------------------------------------------------------------- 1 | # Given an array of integers nums. 2 | # A pair (i,j) is called good if nums[i] == nums[j] and i < j. 3 | # Return the number of good pairs. 4 | 5 | # Example 1: 6 | # Input: nums = [1,2,3,1,1,3] 7 | # Output: 4 8 | # Explanation: There are 4 good pairs (0,3), (0,4), (3,4), (2,5) 0-indexed. 9 | 10 | # Example 2: 11 | # Input: nums = [1,1,1,1] 12 | # Output: 6 13 | # Explanation: Each pair in the array are good. 14 | 15 | # Example 3: 16 | # Input: nums = [1,2,3] 17 | # Output: 0 18 | 19 | # Constraints: 20 | # 1 <= nums.length <= 100 21 | # 1 <= nums[i] <= 100 22 | from typing import List 23 | from collections import Counter 24 | 25 | 26 | class Solution: 27 | def numIdenticalPairs(self, nums: List[int]) -> int: 28 | # list comprehension stores n of occurences of each value in nums 29 | occurences = [val for val in Counter(nums).values()] 30 | num_pairs = 0 # counter variable 31 | 32 | for val in occurences: 33 | if val > 1: # can't make pair if number only occurs once 34 | # (n*(n–1)/2) pairs can be made with this n occurences 35 | num_pairs += val * (val-1)//2 36 | 37 | return num_pairs 38 | -------------------------------------------------------------------------------- /155 - Min Stack.py: -------------------------------------------------------------------------------- 1 | # ------------------------------ 2nd optimal submission ----------------------- 2 | # Your runtime beats 98.90 % of python3 submission 3 | 4 | # 18 / 18 test cases passed. 5 | # Status: Accepted 6 | # Runtime: 52 ms 7 | # Memory Usage: 17.6 MB 8 | 9 | # using 2 stacks AND built-in pop(), append() methods, proved faster than 10 | # implementing a linked list solution ?? 11 | 12 | class MinStack2: 13 | def __init__(self): 14 | self.stack = [] 15 | self.smallest = [9223372036854775807] 16 | 17 | def pop(self): 18 | current = self.stack[-1] 19 | if current == self.smallest[-1]: 20 | self.smallest.pop() 21 | self.stack.pop() 22 | 23 | def push(self, x): 24 | if x <= self.smallest[-1]: 25 | self.smallest.append(x) 26 | self.stack.append(x) 27 | 28 | def top(self): 29 | return self.stack[-1] 30 | 31 | def getMin(self): 32 | return self.smallest[-1] 33 | 34 | # ------------------------------ 1st optimized submission --------------------- 35 | # Your runtime beats 62.03 % of python3 submissions 36 | 37 | # 18 / 18 test cases passed. 38 | # Status: Accepted 39 | # Runtime: 68 ms 40 | # Memory Usage: 18.4 MB 41 | 42 | # implementation of stack data-structure from scratch using linkedlist 43 | # many solutions I seen use a regular [] list with built in pop(), append() methods 44 | 45 | 46 | class Node: 47 | def __init__(self, data=None, next=None): 48 | self.data = data 49 | self.next = next 50 | 51 | 52 | class MinStack: 53 | def __init__(self): 54 | self.head = None 55 | self.smallest = [9223372036854775807] 56 | 57 | def pop(self): 58 | # remove node from head 59 | current = self.head 60 | if current.data == self.smallest[-1]: 61 | self.smallest.pop() 62 | self.head = current.next 63 | current = None 64 | 65 | def push(self, x): 66 | # insert new node between head and first element in the list 67 | # keep track of the smallest number being pushed into the list 68 | if x <= self.smallest[-1]: 69 | self.smallest.append(x) 70 | 71 | new_node = Node(data=x) # initialize new node 72 | new_node.next = self.head 73 | self.head = new_node 74 | 75 | def top(self): 76 | try: 77 | top = self.head.data 78 | except AttributeError: 79 | top = 'Stack is empty' 80 | return top 81 | 82 | def getMin(self): 83 | return self.smallest[-1] 84 | -------------------------------------------------------------------------------- /19 - Remove Nth Node From List.md: -------------------------------------------------------------------------------- 1 | # 19 - Remove Nth Node From List 2 | 3 | Difficulty: medium 4 | Done: Yes 5 | Last edited: March 3, 2022 4:53 PM 6 | Link: https://leetcode.com/problems/remove-nth-node-from-end-of-list/solution/ 7 | Topic: linked list, two pointers 8 | 9 | ## Problem 10 | 11 | --- 12 | 13 | Given the `head` of a linked list, remove the `nth` node from the end of the list and return its head. 14 | 15 | ``` 16 | Input: head = [1,2,3,4,5], n = 2 17 | Output: [1,2,3,5] 18 | ``` 19 | 20 | ![Untitled](images/19-example.png) 21 | 22 | ## Solution 23 | 24 | --- 25 | 26 | From intuition the first process that comes to mind is traversing the list to figure out the length `L`. Once we have length we can get the difference between `n` and length, which should signify the node position to remove. Then we can traverse the list a second time and remove the node after $`L-n`$ steps in the traversal. 27 | 28 | ![Untitled](images/19-1.png) 29 | 30 | Furthermore we will need define a counter after 1st traversal for finding length, and two pointers to keep track of *current* and *previous* once we perform 2nd traversal for removal of `L-n` node. Once we’re at `L-n` steps and remove the node, we can simply break and return head 31 | 32 | ## Whiteboard 33 | 34 | --- 35 | 36 | Find length and incrementing counter L. 37 | 38 | ```python 39 | l = 0 40 | while current is not none: 41 | current = current.next 42 | l += 1 43 | ``` 44 | 45 | once current is at L-n we move pointers, then we can break and return head 46 | 47 | ```python 48 | while current is not None: 49 | if counter == L-n: 50 | previous.next = current.next 51 | return head 52 | ``` 53 | 54 | ![Untitled](images/19-2.png) 55 | 56 | ## Code 57 | 58 | --- 59 | 60 | ```python 61 | # Definition for singly-linked list. 62 | # class ListNode: 63 | # def __init__(self, val=0, next=None): 64 | # self.val = val 65 | # self.next = next 66 | class Solution: 67 | def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]: 68 | 69 | l = 0 70 | current = head 71 | 72 | while current is not None: 73 | current = current.next 74 | l += 1 75 | 76 | current = head 77 | previous = ListNode(-1) 78 | counter = 0 79 | 80 | if l == n: 81 | # edge case where we only have 1 list node 82 | previous.next = current.next 83 | return previous.next 84 | 85 | while current is not None: 86 | if counter == l-n: 87 | # once we reach nth from end 88 | previous.next = current.next 89 | current = previous.next 90 | return head 91 | 92 | else: 93 | #keep traversing 94 | previous = current 95 | current = current.next 96 | 97 | counter += 1 98 | 99 | 100 | 101 | return previous.next 102 | ``` 103 | 104 | ## Time Complexity 105 | 106 | --- 107 | 108 | Having traversed the list the first time to find `L` will take linear time O(n), and the second traversal to remove the `L-n` would also take linear time. Resulting in $O(n) + O(n) = O(2n)$, which can be asymptotically equivalent to $O(n)$ runtime. -------------------------------------------------------------------------------- /203 - Remove Linked List Elements.md: -------------------------------------------------------------------------------- 1 | # Remove Linked List Elements 2 | 3 | Difficulty: easy 4 | Done: Yes 5 | Last edited: February 27, 2022 1:25 AM 6 | Link: https://leetcode.com/problems/remove-linked-list-elements/ 7 | Topic: linked list 8 | 9 | ## Problem 10 | 11 | Given the `head` of a linked list and an integer `val`, remove all the nodes of the linked list that has `Node.val == val`, and return *the new head*. 12 | 13 | ``` 14 | Input: head = [1,2,6,3,4,5,6], val = 6 15 | Output: [1,2,3,4,5] 16 | ``` 17 | 18 | ## Solution 19 | 20 | Similar to linked list reversal using two pointer iterative approach. Whenever the current node in traversals value is equivalent to our target, we point the `previous` node to the `current.next` node. Else, we will continue our traversal. Hereby shifting the previous pointer and current pointer iteratively. 21 | 22 | There’s a caveat, however, whenever the first node of our list is our target —or repeated. Because previous remains undefined. Therefore we need to check if previous is defined beforehand. 23 | 24 | ## Whiteboard 25 | 26 | ![With target value equal to 6](images/203-1.png) 27 | 28 | With target value equal to 6 29 | 30 | ![Problem becomes trickier when target exist as first (or consecutively) node(s)](images/%203-2.png) 31 | 32 | Problem becomes trickier when target exist as first (or consecutively) node(s) 33 | 34 | ## Code 35 | 36 | ```python 37 | # Definition for singly-linked list. 38 | # class ListNode: 39 | # def __init__(self, val=0, next=None): 40 | # self.val = val 41 | # self.next = next 42 | class Solution: 43 | def removeElements(self, head: Optional[ListNode], val: int) -> Optional[ListNode]: 44 | 45 | # for empty list 46 | if head is None: 47 | return None 48 | 49 | current = head 50 | previous = None 51 | 52 | while current is not None: 53 | 54 | if current.val == val: 55 | 56 | if previous is None: 57 | # this will happen when target exist at first node 58 | # or consectuive first (n) nodes 59 | head = head.next 60 | current = head 61 | 62 | if previous: 63 | previous.next = current.next 64 | current.next = None 65 | current = previous.next 66 | 67 | # else keep traversing 68 | else: 69 | previous = current 70 | current = current.next 71 | 72 | 73 | return head 74 | ``` -------------------------------------------------------------------------------- /206 - Reverse Linked List.py: -------------------------------------------------------------------------------- 1 | # Definition for singly-linked list. 2 | # class ListNode: 3 | # def __init__(self, val=0, next=None): 4 | # self.val = val 5 | # self.next = next 6 | class Solution: 7 | def reverseList(self, head: ListNode) -> ListNode: 8 | """will reverse list iteratively, 9 | by traversing and flipping the next pointer of each node 10 | """ 11 | previous_ptr = None # previous pointer, initialized to null 12 | current_ptr = head # current pointer, at head 13 | 14 | while current_ptr is not None: 15 | temp = current_ptr.next # temp buffer, pointing to next node 16 | current_ptr.next = previous_ptr # reverse link of current_ptr to prev 17 | previous_ptr = current_ptr # ---- resume traversal ---- 18 | current_ptr = temp 19 | head = previous_ptr 20 | return head 21 | -------------------------------------------------------------------------------- /21 - Merge Two Sorted Lists.md: -------------------------------------------------------------------------------- 1 | # 21 - Merge Two Sorted Lists 2 | 3 | Difficulty: easy 4 | Done: Yes 5 | Last edited: March 2, 2022 1:53 AM 6 | Link: https://leetcode.com/problems/merge-two-sorted-lists/submissions/ 7 | Topic: linked list 8 | 9 | ## Problem 10 | 11 | --- 12 | 13 | You are given the heads of two sorted linked lists `list1` and `list2`. Merge the two lists in a one **sorted** list. The list should be made by splicing together the nodes of the first two lists. 14 | 15 | Return *the head of the merged linked list*. 16 | 17 | ``` 18 | Input: list1 = [1,2,4], list2 = [1,3,4] 19 | Output: [1,1,2,3,4,4] 20 | ``` 21 | 22 | ![Untitled](images/21-2.png) 23 | 24 | ## Solution 25 | 26 | --- 27 | 28 | Solution can be done in a single iterative traversal, resulting in linear time complexity. To do so we would need to traverse both lists with the use of a pointer —*previous—* which essentially tracks the current place in the final list. 29 | 30 | Additionally we would need to add a sentinel node (hypothetical first node). This allows to functionally make the final merged list never empty. 31 | 32 | The while loop —typical for linked list problems— only runs while l1 or l2 do not point to None. Since 33 | 34 | ## Whiteboard 35 | 36 | --- 37 | 38 | ![Untitled](images/21-1.png) 39 | 40 | ## Code 41 | 42 | --- 43 | 44 | ```python 45 | # Definition for singly-linked list. 46 | # class ListNode: 47 | # def __init__(self, val=0, next=None): 48 | # self.val = val 49 | # self.next = next 50 | class Solution: 51 | def mergeTwoLists(self, list1: Optional[ListNode], list2: Optional[ListNode]) -> Optional[ListNode]: 52 | 53 | # create sentinel node 54 | s = ListNode(0, None) 55 | previous = s 56 | 57 | while list1 is not None and list2 is not None: 58 | # compare value at l1 vs value at l2 59 | # whichever is smaller that's where we point previous, and step that list 60 | # essentially prev keeps track of the new list 61 | 62 | if list1.val <= list2.val: 63 | previous.next = list1 64 | list1 = list1.next 65 | else: 66 | previous.next = list2 67 | list2 = list2.next 68 | 69 | previous = previous.next 70 | 71 | # the while loop only runs while l1 or l2 are not None 72 | 73 | # since lists can be diffent sizes, 74 | # when we've reached the end for one we can point 75 | # the merged list to the non-null list 76 | previous.next = list1 or list2 77 | 78 | return s.next 79 | ``` 80 | 81 | ## Time Complexity 82 | 83 | --- 84 | 85 | big O -------------------------------------------------------------------------------- /21.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | # Definition for singly-linked list. 4 | class ListNode: 5 | def __init__(self, val=0, next=None): 6 | self.val = val 7 | self.next = next 8 | 9 | 10 | class Solution: 11 | def mergeTwoLists(self, list1: Optional[ListNode], list2: Optional[ListNode]) -> Optional[ListNode]: 12 | 13 | # create sentinel node 14 | s = ListNode(0, None) 15 | previous = s 16 | 17 | while list1 is not None and list2 is not None: 18 | # compare value at l1 vs value at l2 19 | # whichever is smaller that's where we point previous, and step that list 20 | # essentially prev keeps track of the new list 21 | 22 | if list1.val <= list2.val: 23 | previous.next = list1 24 | list1 = list1.next 25 | else: 26 | previous.next = list2 27 | list2 = list2.next 28 | 29 | previous = previous.next 30 | 31 | # the while loop only runs while l1 or lx2 are not None 32 | 33 | # since lists can be diffent sizes, 34 | # when we've reached the end for one we can point 35 | # the merged list to the non-null list 36 | previous.next = list1 or list2 37 | 38 | return s.next 39 | 40 | 41 | 42 | l1 = ListNode(val=1, next=ListNode(val=2, next=ListNode(val=3, next=None))) 43 | l2 = ListNode(val=4, next=ListNode(val=5, next=None)) 44 | 45 | s = Solution() 46 | s.mergeTwoLists(list1=l1, list2=l2) -------------------------------------------------------------------------------- /217 - Contains Duplicates.md: -------------------------------------------------------------------------------- 1 | # 217 - Contains Duplicates 2 | 3 | Difficulty: easy 4 | Done: No 5 | Last edited: February 24, 2022 12:13 AM 6 | 7 | ## Problem 8 | 9 | Given an integer array `nums`, return `true` if any value appears **at least twice** in the array, and return `false` if every element is distinct. 10 | 11 | ## Solution 12 | 13 | Naive solution would be to loop through all elements in array and comparing to the rest of the elements in the array, to see if *i* matches *j.* This would result in a O(N^2) solution since we are using performing N times for loop inside N time for loop. 14 | 15 | A better approach would be to run through the array just once, and using additional space to copy over traversed elements to a data structure. If *i* is already in our data structure we raise flag and break, without having to finish traversing all elements, since we only need 1 duplicate. 16 | 17 | ## Code 18 | 19 | ```python 20 | class Solution: 21 | def containsDuplicate(self, nums: List[int]) -> bool: 22 | d = set() 23 | duplicates = False 24 | 25 | while not duplicates: 26 | for num in nums: 27 | if num not in d: 28 | d.add(num) 29 | else: 30 | duplicates = True 31 | break 32 | 33 | return duplicates 34 | ``` -------------------------------------------------------------------------------- /226.py: -------------------------------------------------------------------------------- 1 | # Definition for a binary tree node. 2 | class TreeNode: 3 | def __init__(self, val=0, left=None, right=None): 4 | self.val = val 5 | self.left = left 6 | self.right = right 7 | 8 | 9 | 10 | class Solution: 11 | def invertTree(self, root) -> Optional[TreeNode]: 12 | # do if root is not null 13 | if root: 14 | self.invertTree(root.left) 15 | self.invertTree(root.right) 16 | 17 | root.left, root.right = root.right, root.left 18 | 19 | return root 20 | 21 | 22 | if '__name__' == '__main__': 23 | root = TreeNode(1) 24 | root.left = TreeNode(2) 25 | root.right = TreeNode(3) 26 | root.left.left = TreeNode(4) 27 | root.left.right = TreeNode(5) 28 | root.right.left = TreeNode(6) 29 | root.right.right = TreeNode(7) 30 | 31 | sol = Solution() 32 | sol.invertTree(root) -------------------------------------------------------------------------------- /237 - Delete Node in a Linked List.py: -------------------------------------------------------------------------------- 1 | # Write a function to delete a node (except the tail) in a singly linked list, given only access to that node. 2 | 3 | # Given linked list -- head = [4,5,1,9], which looks like following: 4 | 5 | # Example 1: 6 | # Input: head = [4,5,1,9], node = 5 7 | # Output: [4,1,9] 8 | # Explanation: You are given the second node with value 5, the linked list should become 4 -> 1 -> 9 after calling your function. 9 | 10 | # Example 2: 11 | # Input: head = [4,5,1,9], node = 1 12 | # Output: [4,5,9] 13 | # Explanation: You are given the third node with value 1, the linked list should become 4 -> 5 -> 9 after calling your function. 14 | 15 | # Note: 16 | # The linked list will have at least two elements. 17 | # All of the nodes' values will be unique. 18 | # The given node will not be the tail and it will always be a valid node of the linked list. 19 | # Do not return anything from your function. 20 | 21 | # Definition for singly-linked list. 22 | class ListNode: 23 | def __init__(self, x): 24 | self.val = x 25 | self.next = None 26 | 27 | 28 | class Solution: 29 | def deleteNode(self, node): 30 | """ 31 | :type node: ListNode 32 | :rtype: void Do not return anything, modify node in-place instead. 33 | """ 34 | # node given will not be the tail! 35 | node.val = node.next.val 36 | node.next = node.next.next 37 | return 38 | 39 | -------------------------------------------------------------------------------- /26 - Remove duplicates from sorted array.md: -------------------------------------------------------------------------------- 1 | # 26 - remove duplicates from sorted array 2 | 3 | Difficulty: easy 4 | Done: Yes 5 | Last edited: February 15, 2022 5:53 PM 6 | Link: https://leetcode.com/problems/remove-duplicates-from-sorted-array/ 7 | Topic: two pointers 8 | 9 | ## Problem 10 | 11 | Given an integer array `nums` sorted in **non-decreasing order**, remove the duplicates **[in-place](https://en.wikipedia.org/wiki/In-place_algorithm)** such that each unique element appears only **once**. The **relative order** of the elements should be kept the **same** 12 | 13 | ## Solution 14 | 15 | Similar to #83 but removing duplicates in place requires no additional memory space. We can use a two pointer approach, one pointer to traverse the array and another pointer to traverse the array without duplicates. 16 | 17 | ## Whiteboard 18 | 19 | ![26.png](images/26.png) 20 | 21 | ## Code 22 | 23 | ```python 24 | class Solution: 25 | def removeDuplicates(self, nums: List[int]) -> int: 26 | 27 | k = 1 28 | 29 | for x in range(1, len(nums)): 30 | if nums[x] != nums[x-1]: 31 | nums[k] = nums[x] 32 | k += 1 33 | 34 | return k if len(nums) != 0 else 0 35 | ``` -------------------------------------------------------------------------------- /278 - First Bad Version.md: -------------------------------------------------------------------------------- 1 | # 278 - first bad version 2 | 3 | Difficulty: easy 4 | Done: Yes 5 | Last edited: February 15, 2022 5:28 PM 6 | Topic: binary search 7 | 8 | ## Problem 9 | 10 | You are a product manager and currently leading a team to develop a new product. Unfortunately, the latest version of your product fails the quality check. Since each version is developed based on the previous version, all the versions after a bad version are also bad. 11 | 12 | Suppose you have `n` versions `[1, 2, ..., n]` and you want to find out the first bad one, which causes all the following ones to be bad. 13 | 14 | You are given an API `bool isBadVersion(version)` which returns whether `version` is bad. Implement a function to find the first bad version. You should minimize the number of calls to the API. 15 | 16 | ## Solution 17 | 18 | Perform an iterative binary search, don’t need to allocate space for array 19 | 20 | pseudo 21 | 22 | ```python 23 | define left_ptr, right_ptr 24 | 25 | while left <= right: 26 | define mid = (left+right)//2 27 | 28 | if mid is bad: 29 | if mid-1 is not bad: 30 | mid is first_bad; return 31 | else: 32 | search left 33 | else: 34 | search right 35 | 36 | 37 | return n 38 | 39 | ``` 40 | 41 | ## Whiteboard 42 | 43 | ![Screen Shot 2022-02-15 at 5.14.10 PM.png](images/278.png) 44 | 45 | ## Code 46 | 47 | ```python 48 | # The isBadVersion API is already defined for you. 49 | # def isBadVersion(version: int) -> bool: 50 | 51 | class Solution: 52 | def firstBadVersion(self, n: int) -> int: 53 | left, right = 1, n 54 | 55 | while left <= right: 56 | mid = (left+right) // 2 57 | 58 | if isBadVersion(mid): 59 | if not isBadVersion(mid-1): 60 | # if middle is first bad 61 | return mid 62 | else: 63 | # search left 64 | right = mid-1 65 | else: 66 | #search right 67 | left = mid+1 68 | 69 | return n 70 | ``` 71 | 72 | ## Time Complexity 73 | 74 | Having N elements with Binary search algorithm takes O(logN) -------------------------------------------------------------------------------- /283 - Move Zeroes.py: -------------------------------------------------------------------------------- 1 | # 283. Move Zeroes 2 | # Easy 3 | # Given an array nums, write a function to move all 0's to the end of it while maintaining the relative order of the non-zero elements. 4 | 5 | # Example: 6 | # Input: [0,1,0,3,12] 7 | # Output: [1,3,12,0,0] 8 | 9 | # Note: 10 | # You must do this in-place without making a copy of the array. 11 | # Minimize the total number of operations. 12 | from typing import List 13 | 14 | 15 | class Solution: 16 | def moveZeroes(self, nums: List[int]) -> None: 17 | """ 18 | Do not return anything, modify nums in-place instead. 19 | """ 20 | for num in nums: 21 | if num == 0: 22 | nums.remove(num) 23 | nums.append(num) 24 | -------------------------------------------------------------------------------- /3 - Longest Substring Without Repeating Characters.md: -------------------------------------------------------------------------------- 1 | # 3 - Longest Substring Without Repeating Characters 2 | 3 | Difficulty: medium 4 | Done: Yes 5 | Last edited: February 18, 2022 2:06 PM 6 | Link: https://leetcode.com/problems/longest-substring-without-repeating-characters/ 7 | Topic: set, sliding window 8 | 9 | ## Problem 10 | 11 | Given a string `s`, find the length of the **longest substring** without repeating characters. 12 | 13 | Example 1: 14 | 15 | ``` 16 | Input: s = "abcabcbb" 17 | Output: 3 18 | Explanation: The answer is "abc", with the length of 3. 19 | 20 | ``` 21 | 22 | Example 2 23 | 24 | ``` 25 | Input: s = "bbbbb" 26 | Output: 1 27 | Explanation: The answer is "b", with the length of 1. 28 | 29 | ``` 30 | 31 | Example 3 32 | 33 | ``` 34 | Input: s = "pwwkew" 35 | Output: 3 36 | Explanation: The answer is "wke", with the length of 3. 37 | Notice that the answer must be a substring, "pwke" is a subsequence and not a substring. 38 | 39 | ``` 40 | 41 | Constraints 42 | 43 | - `0 <= s.length <= 5 * 104` 44 | - `s` consists of English letters, digits, symbols and spaces. 45 | 46 | ## Solution 47 | 48 | Intuitively I was attempting to use a hashtable, and buffer variable. Looping through array and adding current element to buffer, stoping when we reach a duplicate insider our buffer, then copying the buffer into our hashtable. However, it became complicated as far as string manipulation. 49 | 50 | A better approach is to use a **sliding window** algorithm with two pointers, and a set which allows for unique elements. Found algorithm to be very similar to my initial approach, with the exception that using sliding window we easily remove the left-most duplicate element in the current window. 51 | 52 | Then the size of the window at the largest point can be used to return to the largest substring, through each iteration we compare the current size of the set to the *longest* variable and overwrite if necessary 53 | 54 | ```python 55 | if len(charset) > longest: 56 | longest = len(charset) 57 | ``` 58 | 59 | ## Whiteboard 60 | 61 | ![Screen Shot 2022-02-18 at 1.03.31 PM.png](images/3-1.png) 62 | 63 | ![Screen Shot 2022-02-18 at 1.03.50 PM.png](images/3-2.png) 64 | 65 | ## Code 66 | 67 | ```python 68 | buffer = [] 69 | subs = [] 70 | 71 | if len(s) == 1: 72 | return 1 73 | elif len(s) == 0: 74 | return 0 75 | 76 | for i in range(len(s)): 77 | if s[i] not in buffer: 78 | buffer.append(s[i]) 79 | else: 80 | subs.append(''.join(buffer)) 81 | buffer.clear() 82 | buffer.append(s[i]) 83 | 84 | subs.append(''.join(buffer)) 85 | 86 | return len(max(subs, key=len)) 87 | ``` 88 | 89 | ```python 90 | class Solution: 91 | def lengthOfLongestSubstring(self, s: str) -> int: 92 | # sliding window approach requiring two pointers 93 | # use set to hold current window values 94 | left = 0 95 | right = 0 96 | longest = 0 97 | charset = set() 98 | 99 | for right in range(len(s)): 100 | while s[right] in charset: 101 | charset.remove(s[left]) 102 | left += 1 103 | 104 | charset.add(s[right]) 105 | 106 | if len(charset) > longest: 107 | # current set is larger than longest, overwrite 108 | # eventually longest will be hold size of largest charset 109 | longest = len(charset) 110 | 111 | return longest 112 | ``` 113 | -------------------------------------------------------------------------------- /3.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def lengthOfLongestSubstring(self, s: str) -> int: 3 | # sliding window approach requiring two pointers 4 | # set variable containing all unique 5 | left = 0 6 | right = 0 7 | longest = 0 8 | charset = set() 9 | 10 | for right in range(len(s)): 11 | while s[right] in charset: 12 | # look for duplicate 13 | charset.remove(s[left]) 14 | left += 1 15 | 16 | charset.add(s[right]) 17 | if len(charset) > longest: 18 | longest = len(charset) 19 | 20 | return longest 21 | 22 | 23 | if __name__ == '__main__': 24 | obj = Solution() 25 | obj.lengthOfLongestSubstring(s = "abcabcbb") 26 | -------------------------------------------------------------------------------- /35 - Search Insert Position.md: -------------------------------------------------------------------------------- 1 | # 35 - Search Insert Position 2 | 3 | Difficulty: easy 4 | Done: Yes 5 | Last edited: February 16, 2022 5:09 PM 6 | Link: https://leetcode.com/problems/search-insert-position/ 7 | Topic: array, binary search 8 | 9 | ## Problem 10 | 11 | Given a sorted array of distinct integers and a target value, return the index if the target is found. If not, return the index where it would be if it were inserted in order. 12 | 13 | You must write an algorithm with `O(log n)` runtime complexity. 14 | 15 | ## Solution 16 | 17 | Straight away we can say this will require a **binary search** approach to accomplish a runtime complexity of $O(log*n)$. Three pointer approach to keep track of left, right, and midpoint elements of sorted array. 18 | 19 | We want to return index of target, which will be tracked by midpoint value. Only constraint is if target is not in array, then we want to return the index of where it would be inserted 20 | 21 | ## Whiteboard 22 | 23 | ![solution if target in array](images/35-1.png) 24 | 25 | solution if target in array 26 | 27 | ![target = 7, not in array, return left ptr](images/35-2.png) 28 | 29 | target = 7, not in array, return left ptr 30 | 31 | ## Code 32 | 33 | ```python 34 | class Solution: 35 | def searchInsert(self, nums: List[int], target: int) -> int: 36 | 37 | left, right = 0, len(nums)-1 38 | 39 | while left <= right: 40 | mid = (left+right) // 2 41 | if target == nums[mid]: 42 | return mid 43 | elif target > nums[mid]: 44 | # search right 45 | left = mid + 1 46 | elif target < nums[mid]: 47 | # search left 48 | right = mid - 1 49 | 50 | return left 51 | ``` -------------------------------------------------------------------------------- /567 - Permutation in String.py: -------------------------------------------------------------------------------- 1 | # 567. Permutation in String 2 | # Medium 3 | # Given two strings s1 and s2, write a function to return true if s2 contains the permutation of s1. In other words, one of the first string's permutations is the substring of the second string. 4 | 5 | # Example 1: 6 | # Input: s1 = "ab" s2 = "eidbaooo" 7 | # Output: True 8 | # Explanation: s2 contains one permutation of s1 ("ba"). 9 | 10 | # Example 2: 11 | # Input:s1= "ab" s2 = "eidboaoo" 12 | # Output: False 13 | 14 | # Constraints: 15 | # The input strings only contain lower case letters. 16 | # The length of both given strings is in range [1, 10,000]. 17 | 18 | 19 | class Solution: 20 | def checkInclusion(self, s1: str, s2: str) -> bool: 21 | if len(s1) != len(s2): 22 | return False 23 | 24 | return sorted(s1) == sorted(s2) 25 | 26 | -------------------------------------------------------------------------------- /7 - Reverse Integer.py: -------------------------------------------------------------------------------- 1 | # 7. Reverse Integer 2 | # Easy 3 | # Given a 32-bit signed integer, reverse digits of an integer. 4 | 5 | # Example 1: 6 | # Input: 123 7 | # Output: 321 8 | 9 | # Example 2: 10 | # Input: -123 11 | # Output: -321 12 | 13 | # Example 3: 14 | # Input: 120 15 | # Output: 21 16 | 17 | # Note: 18 | # Assume we are dealing with an environment which could only store integers 19 | # within the 32-bit signed integer range: [−231, 231 − 1]. For the purpose of 20 | # this problem, assume that your function returns 0 when the 21 | # reversed integer overflows. 22 | 23 | 24 | class Solution: 25 | def reverse(self, x: int) -> int: 26 | 27 | if x < 0: 28 | num_str = str(x)[1:][::-1] 29 | reversed_x = int('-' + num_str) 30 | else: 31 | num_str = str(x)[::-1] 32 | reversed_x = int(num_str) 33 | 34 | if reversed_x >= 2**31 - 1 or reversed_x <= -2**31: 35 | return 0 36 | 37 | return reversed_x 38 | -------------------------------------------------------------------------------- /704 - Binary Search.md: -------------------------------------------------------------------------------- 1 | # 704. Binary Search 2 | 3 | Difficulty: easy 4 | Done: Yes 5 | Last edited: February 12, 2022 5:53 PM 6 | Link: https://leetcode.com/problems/binary-search/ 7 | Topic: binary search 8 | 9 | ## Problem 10 | 11 | Given an array of integers `nums` which is sorted in ascending order, and an integer `target`, write a function to search `target` in `nums`. If `target` exists, then return its index. Otherwise, return `-1`. 12 | 13 | ## Solution 14 | 15 | goal of the algorithm is to divide array in half, if our `target` is smaller than current then we take the left side of the array, if `target` is larger than the *current* then we take the right side of the array. Repeat 16 | 17 | ## Whiteboard 18 | 19 | ![target = 9](images/Screen_Shot_2022-02-12_at_5.36.32_PM.png) 20 | 21 | target = 9 22 | 23 | ![target = 2 (not existing)](images/Screen_Shot_2022-02-12_at_5.36.32_PM.png) 24 | 25 | target = 2 (not existing) 26 | 27 | ## Code 28 | 29 | ```python 30 | class Solution: 31 | def search(self, nums: List[int], target: int) -> int: 32 | 33 | try: 34 | i = nums.index(target) 35 | except: 36 | i = -1 37 | 38 | return i 39 | ``` 40 | 41 | ```python 42 | class Solution: 43 | def search(self, nums: List[int], target: int) -> int: 44 | # iteratively 45 | 46 | left = 0 47 | right = len(nums) - 1 48 | while left <= right: 49 | middle = left + (right-left) // 2 50 | 51 | if nums[middle] == target: 52 | return middle 53 | 54 | if target < nums[middle]: 55 | # use left side 56 | right = middle - 1 57 | 58 | if target > nums[middle]: 59 | # use right side 60 | left = middle + 1 61 | 62 | return -1 63 | 64 | ``` 65 | 66 | ## Time Complexity 67 | 68 | Having N elements with Binary search algorithm takes O(logN) 69 | -------------------------------------------------------------------------------- /83 - Remove Duplicates from Sorted List.py: -------------------------------------------------------------------------------- 1 | # Definition for singly-linked list. 2 | # class ListNode: 3 | # def __init__(self, val=0, next=None): 4 | # self.val = val 5 | # self.next = next 6 | class Solution: 7 | def deleteDuplicates(self, head: ListNode) -> ListNode: 8 | """Runner pointer traversal, passing node values to hashmap with duplicate keys. 9 | If key already present --hence, unique-- 'delete' that node 10 | """ 11 | previous = None 12 | current = head 13 | nodes_dict = {} 14 | 15 | while current is not None: 16 | if current.val not in nodes_dict: 17 | nodes_dict[current.val] = 1 18 | previous = current 19 | else: 20 | previous.next = current.next 21 | 22 | current = current.next 23 | 24 | return head 25 | -------------------------------------------------------------------------------- /9 - Palindrome Number.py: -------------------------------------------------------------------------------- 1 | # Determine whether an integer is a palindrome. 2 | # An integer is a palindrome when it reads the same backward as forward. 3 | 4 | # Example 1: 5 | # Input: 121 6 | # Output: true 7 | 8 | # Example 2: 9 | # Input: -121 10 | # Output: false 11 | # Explanation: From left to right, it reads -121. From right to left, it 12 | # becomes 121-. Therefore it is not a palindrome. 13 | 14 | # Example 3: 15 | # Input: 10 16 | # Output: false 17 | # Explanation: Reads 01 from right to left. Therefore it is not a palindrome. 18 | 19 | # Follow up: 20 | # Coud you solve it without converting the integer to a string? 21 | 22 | 23 | class Solution: 24 | def isPalindrome(self, x: int) -> bool: 25 | # negatives are false 26 | if x < 0: 27 | return False 28 | 29 | x_copy, x_reversed = x, 0 30 | while x_copy: 31 | x_reversed = x_reversed * 10 + x_copy % 10 32 | x_copy = x_copy // 10 # wil remove digit from x_copy until it becomes 0 33 | 34 | return x == x_reversed 35 | -------------------------------------------------------------------------------- /94 - Binary Tree Inorder Traversal.md: -------------------------------------------------------------------------------- 1 | # 94 - Binary Tree Inorder Traversal 2 | 3 | Difficulty: easy 4 | Done: Yes 5 | Last edited: March 13, 2022 10:05 PM 6 | Link: https://leetcode.com/problems/binary-tree-inorder-traversal/ 7 | Topic: recursion, tree 8 | 9 | ## Problem 10 | 11 | --- 12 | 13 | Given the `root` of a binary tree, return *the inorder traversal of its nodes' values*. 14 | 15 | ``` 16 | Input: root = [1,null,2,3] 17 | Output: [1,3,2] 18 | ``` 19 | 20 | ![Untitled](94%20-%20Binar%20a70d4/Untitled.png) 21 | 22 | ## Solution 23 | 24 | --- 25 | 26 | in order traversal of binary tree requires to visit left child node parent node, then right child node, in that order. Will do so recursively, we know to print when node is a leaf node 27 | 28 | ## Whiteboard 29 | 30 | --- 31 | 32 | ![Untitled](94%20-%20Binar%20a70d4/Untitled%201.png) 33 | 34 | ## Code 35 | 36 | --- 37 | 38 | ```python 39 | # Definition for a binary tree node. 40 | # class TreeNode: 41 | # def __init__(self, val=0, left=None, right=None): 42 | # self.val = val 43 | # self.left = left 44 | # self.right = right 45 | class Solution: 46 | 47 | def __init__(self): 48 | self.res = [] 49 | 50 | def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]: 51 | # in order traversal of binary tree requires to visit left child node, 52 | # parent node, then right child node. In that order 53 | 54 | # will do so recursively 55 | # we know to print when node is a leaf node 56 | 57 | if root is None: 58 | return [] 59 | 60 | else: 61 | return self.inorderTraversal(root.left) + [root.val] + self.inorderTraversal(root.right) 62 | ``` 63 | 64 | ## Time Complexity 65 | 66 | --- 67 | 68 | The time complexity is O(n)*O*(*n*) because the recursive function is $T(n)=2⋅T(n/2)+1T(n)=2⋅T(n/2)+1$. -------------------------------------------------------------------------------- /977 - Squares Of A Sorted Array.md: -------------------------------------------------------------------------------- 1 | # 977 - Squares Of A Sorted Array 2 | 3 | Difficulty: easy 4 | Done: No 5 | Last edited: February 17, 2022 12:47 PM 6 | Topic: two pointers 7 | 8 | ## Problem 9 | 10 | Given an integer array `nums` sorted in **non-decreasing** order, return *an array of **the squares of each number** sorted in non-decreasing order*. 11 | 12 | Example 1: 13 | 14 | ``` 15 | Input: nums = [-4,-1,0,3,10] 16 | Output: [0,1,9,16,100] 17 | Explanation: After squaring, the array becomes [16,1,0,9,100]. 18 | After sorting, it becomes [0,1,9,16,100]. 19 | 20 | ``` 21 | 22 | Example 2: 23 | 24 | ``` 25 | Input: nums = [-7,-3,2,3,11] 26 | Output: [4,9,9,49,121] 27 | 28 | ``` 29 | 30 | Constraints: 31 | 32 | - `1 <= nums.length <= 104` 33 | - `104 <= nums[i] <= 104` 34 | - `nums` is sorted in **non-decreasing** order. 35 | 36 | ## Solution 37 | 38 | lorem ipsum 39 | 40 | ## Whiteboard 41 | 42 | [http://excalidraw.com](http://excalidraw.com) 43 | 44 | ## Code 45 | 46 | ```python 47 | class Solution: 48 | def sortedSquares(self, nums: List[int]) -> List[int]: 49 | return sorted([x**2 for x in nums]) 50 | ``` 51 | 52 | using built-in sorted 53 | 54 | ```python 55 | class Solution: 56 | def sortedSquares(self, nums: List[int]) -> List[int]: 57 | left, right = 0, len(nums)-1 58 | 59 | while left <= right: 60 | 61 | max_abs = max(nums[left:], key=abs) 62 | 63 | nums.insert(0, nums.pop(nums.index(max_abs))) 64 | nums[0] = nums[0]**2 65 | left += 1 66 | 67 | return nums 68 | ``` 69 | 70 | custom 2 pointer approach 71 | -------------------------------------------------------------------------------- /977.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def sortedSquares(self, nums): 3 | left, right = 0, len(nums)-1 4 | 5 | stack = [] 6 | 7 | while left <= right: 8 | max_abs = max(nums, key=abs) 9 | nums.remove(max_abs) 10 | stack.insert(0, abs(max_abs)**2) 11 | left += 1 12 | 13 | return stack 14 | 15 | 16 | if __name__ == '__main__': 17 | s = Solution() 18 | s.sortedSquares(nums = [-3, -3, 0,0, 1, 10]) 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Leetcode solutions (Python) 2 | Tracking and saving progress with Notion, [here](https://brianruiz.notion.site/751a887acb624538b5f7f500f7cdf944?v=118114dd18394f6497902e1ed9e9a734)!! Feel free to duplicate and re-use the template 3 | 4 | ## Problems list screenshot 5 | ![Screen Shot 2022-03-03 at 4 58 26 PM](https://user-images.githubusercontent.com/23439187/156667046-24e532e7-a43b-4ba9-b5f5-4bdd8ce1eda3.png) 6 | 7 | ## Problem detail example 8 | image 9 | -------------------------------------------------------------------------------- /coding-challenge-august/week 1/Add and Search Word.py: -------------------------------------------------------------------------------- 1 | # Design a data structure that supports the following two operations: 2 | 3 | # void addWord(word) 4 | # bool search(word) 5 | # search(word) can search a literal word or a regular expression string containing only letters a-z or .. A . means it can represent any one letter. 6 | 7 | # Example: 8 | # addWord("bad") 9 | # addWord("dad") 10 | # addWord("mad") 11 | # search("pad") -> false 12 | # search("bad") -> true 13 | # search(".ad") -> true 14 | # search("b..") -> true 15 | 16 | # Note: 17 | # You may assume that all words are consist of lowercase letters a-z. 18 | 19 | class WordDictionary: 20 | 21 | def __init__(self): 22 | """ 23 | Initialize your data structure here. 24 | """ 25 | self.trie = {} 26 | 27 | def __repr__(self): 28 | return repr(self.trie) 29 | 30 | def addWord(self, word: str) -> None: 31 | """ 32 | Adds a word into the data structure. 33 | """ 34 | node = self.trie 35 | for letter in word: 36 | if letter not in node: 37 | node[letter] = {} 38 | node = node[letter] 39 | node['*'] = True # denotes a completed word 40 | 41 | def search(self, word: str) -> bool: 42 | """ 43 | Returns if the word is in the data structure. A word could contain the dot character '.' to represent any one letter. 44 | """ 45 | return self.searchNode(self.trie, word) 46 | 47 | def searchNode(self, node, word: str) -> bool: 48 | for index, letter in enumerate(word): 49 | if letter == '.': 50 | return any(self.searchNode(node[w], word[index+1:]) for w in node if w != '*') 51 | if letter not in node: return False 52 | node = node[letter] 53 | return '*' in node 54 | 55 | # Your WordDictionary object will be instantiated and called as such: 56 | # obj = WordDictionary() 57 | # obj.addWord(word) 58 | # param_2 = obj.search(word) -------------------------------------------------------------------------------- /coding-challenge-august/week 1/Design Hashset.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrianRuizy/leetcode-notion/0b4d8c38b6a0242038fadb61f5a2c36bdf39e090/coding-challenge-august/week 1/Design Hashset.py -------------------------------------------------------------------------------- /coding-challenge-august/week 1/Detect Capital.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrianRuizy/leetcode-notion/0b4d8c38b6a0242038fadb61f5a2c36bdf39e090/coding-challenge-august/week 1/Detect Capital.py -------------------------------------------------------------------------------- /coding-challenge-august/week 1/Find All Duplicates.py: -------------------------------------------------------------------------------- 1 | # Given an array of integers, 1 ≤ a[i] ≤ n (n = size of array), some elements appear twice and others appear once. 2 | 3 | # Find all the elements that appear twice in this array. 4 | 5 | # Could you do it without extra space and in O(n) runtime? 6 | 7 | # Example: 8 | # Input: 9 | # [4,3,2,7,8,2,3,1] 10 | 11 | # Output: 12 | # [2,3] 13 | 14 | from typing import List 15 | 16 | 17 | class Solution: 18 | def findDuplicates(self, nums: List[int]) -> List[int]: 19 | my_dict = {} 20 | duplicates = [] 21 | 22 | # traverse nums list linearly 23 | for x in nums: 24 | if x in my_dict: 25 | # if x is already in hash table, 26 | # add x to duplicates list 27 | duplicates.append(x) 28 | else: 29 | # append every x value to hash table, if not already there 30 | # note: dictionary keys must be unique which aids our algorithm 31 | my_dict[x] = None 32 | 33 | return duplicates 34 | 35 | # Runtime beats 96.27 % of python3 submissions! 36 | -------------------------------------------------------------------------------- /coding-challenge-august/week 1/Power of Four.py: -------------------------------------------------------------------------------- 1 | from math import log 2 | class Solution: 3 | def isPowerOfFour(self, num: int) -> bool: 4 | # True if num is not 0, AND log₄(num) is a whole-number 5 | return num > 0 and log(num, 4).is_integer() -------------------------------------------------------------------------------- /coding-challenge-august/week 1/Valid Palindrome.py: -------------------------------------------------------------------------------- 1 | """Given a string, determine if it is a palindrome, 2 | considering only alphanumeric characters and ignoring cases. 3 | 4 | Note: For the purpose of this problem, we define empty string as valid palindrome. 5 | 6 | Example 1: 7 | Input: "A man, a plan, a canal: Panama" 8 | Output: true 9 | 10 | Example 2: 11 | Input: "race a car" 12 | Output: false 13 | 14 | Constraints: 15 | 's' consists only of printable ASCII characters. 16 | """ 17 | import re 18 | 19 | class Solution: 20 | def isPalindrome(self, s: str) -> bool: 21 | # empty str is valid 22 | if not s: 23 | print('Empty string valid') 24 | return True 25 | 26 | elif s: 27 | # regex makes string alphanumeric, and drops underscores 28 | # to remove spaces and capitalize 29 | s = re.sub(r'[\W\_]', '', s) 30 | s = s.upper().replace(' ', '') 31 | print(f'str: {s}') 32 | 33 | if s == s[::-1]: 34 | return True 35 | else: 36 | return False 37 | -------------------------------------------------------------------------------- /coding-challenge-august/week 1/Vertical Order Traversal of a Binary Tree.py: -------------------------------------------------------------------------------- 1 | # Given a binary tree, return the vertical order traversal of its nodes values. 2 | # For each node at position (X, Y), its left and right children respectively will be at positions (X-1, Y-1) and (X+1, Y-1). 3 | # Running a vertical line from X = -infinity to X = +infinity, whenever the vertical line touches some nodes, 4 | # we report the values of the nodes in order from top to bottom (decreasing Y coordinates). 5 | # If two nodes have the same position, then the value of the node that is reported first is the value that is smaller. 6 | # Return an list of non-empty reports in order of X coordinate. Every report will have a list of values of nodes. 7 | 8 | from collections import defaultdict 9 | from typing import List 10 | 11 | 12 | class TreeNode: 13 | # Definition for a binary tree node. 14 | 15 | def __init__(self, val=0, left=None, right=None): 16 | self.val = val 17 | self.left = left 18 | self.right = right 19 | 20 | 21 | class Solution: 22 | def verticalTraversal(self, root: TreeNode) -> List[List[int]]: 23 | if not root: 24 | return 25 | 26 | # Create a dictionary to store vertical order of binary tree nodes 27 | mapping = defaultdict(list) 28 | 29 | # create an empty queue for level order traversal 30 | # enqueue root node with horizontal distance as 0 31 | queue = [(root, 0)] 32 | 33 | while queue: 34 | tmp = [] 35 | dic = defaultdict(list) 36 | 37 | for node, s in queue: 38 | dic[s].append(node.val) 39 | if node.left: 40 | tmp += (node.left, s-1), 41 | if node.right: 42 | tmp += (node.right, s+1), 43 | 44 | for i in dic: 45 | mapping[i].extend(sorted(dic[i])) 46 | 47 | queue = tmp 48 | 49 | return [mapping[i] for i in sorted(mapping)] 50 | -------------------------------------------------------------------------------- /coding-challenge-august/week 1/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrianRuizy/leetcode-notion/0b4d8c38b6a0242038fadb61f5a2c36bdf39e090/coding-challenge-august/week 1/__init__.py -------------------------------------------------------------------------------- /coding-challenge-august/week 2/Excel Sheet Column Number.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def titleToNumber(self, s: str) -> int: 3 | total = 0 4 | 5 | # Example: 6 | # s = 'CDA' --> ord(C)*26*26 + ord(D)*26 + ord(A) = 2133 7 | for exponent, letter in enumerate(s[::-1]): 8 | total += (ord(letter)-64)*26**exponent 9 | 10 | return total 11 | -------------------------------------------------------------------------------- /coding-challenge-august/week 2/Pascal's Triangle II.py: -------------------------------------------------------------------------------- 1 | # Given a non-negative index k where k ≤ 33, return the kth index row of the Pascal's triangle. 2 | 3 | # Note that the row index starts from 0. 4 | # In Pascal's triangle, each number is the sum of the two numbers directly above it. 5 | 6 | # Example: 7 | # Input: 3 8 | # Output: [1,3,3,1] 9 | # Follow up: 10 | 11 | # Could you optimize your algorithm to use only O(k) extra space? 12 | from typing import List 13 | 14 | 15 | class Solution: 16 | def getRow(self, rowIndex: int) -> List[List[int]]: 17 | if rowIndex == 1: 18 | return [1, 1] 19 | 20 | elif rowIndex == 2: 21 | return [1, 2, 1] 22 | 23 | else: 24 | triangle = [[1], [1, 1]] 25 | for i in range(1, rowIndex): 26 | current_row = [1] 27 | j = 0 28 | while j < i: 29 | current_row.append(triangle[i][j] + triangle[i][j+1]) 30 | j += 1 31 | 32 | current_row.append(1) 33 | triangle.append(current_row) 34 | 35 | return triangle[rowIndex] 36 | -------------------------------------------------------------------------------- /coding-challenge-august/week 2/Path Sum III.py: -------------------------------------------------------------------------------- 1 | from collections import defaultdict 2 | 3 | 4 | # Definition for a binary tree node. 5 | # class TreeNode: 6 | # def __init__(self, val=0, left=None, right=None): 7 | # self.val = val 8 | # self.left = left 9 | # self.right = right 10 | 11 | 12 | class Solution: 13 | def pathSum(self, root, sum): 14 | self.result, self.count = 0, defaultdict(int) 15 | self.count[sum] = 1 16 | self.depthFirstSearch(root, sum, 0) 17 | return self.result 18 | 19 | def depthFirstSearch(self, root, sum, root_sum): 20 | if not root: 21 | return None 22 | 23 | root_sum += root.val 24 | self.result += self.count[root_sum] 25 | self.count[root_sum + sum] += 1 26 | self.depthFirstSearch(root.left, sum, root_sum) 27 | self.depthFirstSearch(root.right, sum, root_sum) 28 | self.count[root_sum + sum] -= 1 29 | -------------------------------------------------------------------------------- /coding-challenge-august/week 2/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrianRuizy/leetcode-notion/0b4d8c38b6a0242038fadb61f5a2c36bdf39e090/coding-challenge-august/week 2/__init__.py -------------------------------------------------------------------------------- /images/19-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrianRuizy/leetcode-notion/0b4d8c38b6a0242038fadb61f5a2c36bdf39e090/images/19-1.png -------------------------------------------------------------------------------- /images/19-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrianRuizy/leetcode-notion/0b4d8c38b6a0242038fadb61f5a2c36bdf39e090/images/19-2.png -------------------------------------------------------------------------------- /images/19-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrianRuizy/leetcode-notion/0b4d8c38b6a0242038fadb61f5a2c36bdf39e090/images/19-example.png -------------------------------------------------------------------------------- /images/203-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrianRuizy/leetcode-notion/0b4d8c38b6a0242038fadb61f5a2c36bdf39e090/images/203-1.png -------------------------------------------------------------------------------- /images/203-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrianRuizy/leetcode-notion/0b4d8c38b6a0242038fadb61f5a2c36bdf39e090/images/203-2.png -------------------------------------------------------------------------------- /images/21-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrianRuizy/leetcode-notion/0b4d8c38b6a0242038fadb61f5a2c36bdf39e090/images/21-1.png -------------------------------------------------------------------------------- /images/21-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrianRuizy/leetcode-notion/0b4d8c38b6a0242038fadb61f5a2c36bdf39e090/images/21-2.png -------------------------------------------------------------------------------- /images/26.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrianRuizy/leetcode-notion/0b4d8c38b6a0242038fadb61f5a2c36bdf39e090/images/26.png -------------------------------------------------------------------------------- /images/278.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrianRuizy/leetcode-notion/0b4d8c38b6a0242038fadb61f5a2c36bdf39e090/images/278.png -------------------------------------------------------------------------------- /images/3-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrianRuizy/leetcode-notion/0b4d8c38b6a0242038fadb61f5a2c36bdf39e090/images/3-1.png -------------------------------------------------------------------------------- /images/3-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrianRuizy/leetcode-notion/0b4d8c38b6a0242038fadb61f5a2c36bdf39e090/images/3-2.png -------------------------------------------------------------------------------- /images/35-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrianRuizy/leetcode-notion/0b4d8c38b6a0242038fadb61f5a2c36bdf39e090/images/35-1.png -------------------------------------------------------------------------------- /images/35-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrianRuizy/leetcode-notion/0b4d8c38b6a0242038fadb61f5a2c36bdf39e090/images/35-2.png -------------------------------------------------------------------------------- /images/94-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrianRuizy/leetcode-notion/0b4d8c38b6a0242038fadb61f5a2c36bdf39e090/images/94-1.png -------------------------------------------------------------------------------- /images/94-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrianRuizy/leetcode-notion/0b4d8c38b6a0242038fadb61f5a2c36bdf39e090/images/94-2.png -------------------------------------------------------------------------------- /images/Screen_Shot_2022-02-12_at_5.36.32_PM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrianRuizy/leetcode-notion/0b4d8c38b6a0242038fadb61f5a2c36bdf39e090/images/Screen_Shot_2022-02-12_at_5.36.32_PM.png -------------------------------------------------------------------------------- /images/Screen_Shot_2022-02-12_at_5.36.49_PM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrianRuizy/leetcode-notion/0b4d8c38b6a0242038fadb61f5a2c36bdf39e090/images/Screen_Shot_2022-02-12_at_5.36.49_PM.png -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrianRuizy/leetcode-notion/0b4d8c38b6a0242038fadb61f5a2c36bdf39e090/requirements.txt --------------------------------------------------------------------------------