Leetcode

¡Supera tus tareas y exámenes ahora con Quizwiz!

input: two Tree nodes output: True of False test cases: Assumption: No Data Structure: No Algorithm: Recursion Time complexity: O(N) Space complexity: O(log N) class Solution(object): def isSameTree(self, p, q): if p is None and q is None: return True if p is None or q is None or p.val != q.val: return False return self.isSameTree(p.right, q.right) and self.isSameTree(p.left, q.left)

100. Same Tree Given two binary trees, write a function to check if they are the same or not. Two binary trees are considered the same if they are structurally identical and the nodes have the same value.

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def longestOnes(self, A, K): p1, res = 0, 0 num_zero = 0 for p2 in range(len(A)): if A[p2] == 0: num_zero += 1 if num_zero > K: if A[p1] == 0: num_zero -= 1 p1 += 1 res = max(res, p2-p1+1) return res

1004. Max Consecutive Ones III Given an array A of 0s and 1s, we may change up to K values from 0 to 1. Return the length of the longest (contiguous) subarray that contains only 1s. Example 1: Input: A = [1,1,1,0,0,0,1,1,1,1,0], K = 2 Output: 6 Explanation: [1,1,1,0,0,1,1,1,1,1,1] Bolded numbers were flipped from 0 to 1. The longest subarray is underlined.

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def lengthOfLIS(self, nums): n = len(nums) if n == 0: return 0 dp = [1] * n for i in range(1, n): for j in range(i, -1, -1): if nums[j] < nums[i]: dp[i] = max(dp[i], dp[j] + 1) return max(dp)

300. Longest Increasing Subsequence Given an unsorted array of integers, find the length of longest increasing subsequence. Example: Input: [10,9,2,5,3,7,101,18] Output: 4 Explanation: The longest increasing subsequence is [2,3,7,101], therefore the length is 4.

Data Structure: Algorithm: Time complexity: Space complexity: class StreamChecker(object): def __init__(self, words): self.max_len = -float('inf') for w in words: self.max_len = max(len(w), self.max_len) self.trie = self.construct_trie(words) self.q = deque() def construct_trie(self, words): root = {} for w in words: level = root for c in w[::-1]: if c not in level: level[c] = {} level = level[c] level['#'] = True return root def search_trie(self, word): level = self.trie for c in word[::-1]: if '#' in level: return True if c in level: level = level[c] else: return False return True if '#' in level else False def query(self, letter): self.q.append(letter) if len(self.q) > self.max_len: self.q.popleft() word = list(self.q) return self.search_trie(word)

1032. Stream of Characters Implement the StreamChecker class as follows: 1. StreamChecker(words): Constructor, init the data structure with the given words. 2. query(letter): returns true if and only if for some k >= 1, the last k characters queried (in order from oldest to newest, including this letter just queried) spell one of the words in the given list. Example: StreamChecker streamChecker = new StreamChecker(["cd","f","kl"]); // init the dictionary. streamChecker.query('a'); // return false streamChecker.query('b'); // return false streamChecker.query('c'); // return false streamChecker.query('d'); // return true, because 'cd' is in the wordlist streamChecker.query('e'); // return false streamChecker.query('f'); // return true, because 'f' is in the wordlist streamChecker.query('g'); // return false streamChecker.query('h'); // return false streamChecker.query('i'); // return false streamChecker.query('j'); // return false streamChecker.query('k'); // return false streamChecker.query('l'); // return true, because 'kl' is in the wordlist

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def assignBikes(self, workers, bikes): dist = [] res = [-1] * len(workers) bike_used = set() for i, w in enumerate(workers): for j, b in enumerate(bikes): dist.append((abs(w[0] - b[0]) + abs(w[1] - b[1]), i, j)) dist.sort() for d, i, j in dist: if res[i] == -1 and j not in bike_used: res[i] = j bike_used.add(j) return res

1057. Campus Bikes On a campus represented as a 2D grid, there are N workers and M bikes, with N <= M. Each worker and bike is a 2D coordinate on this grid. Our goal is to assign a bike to each worker. Among the available bikes and workers, we choose the (worker, bike) pair with the shortest Manhattan distance between each other, and assign the bike to that worker. (If there are multiple (worker, bike) pairs with the same shortest Manhattan distance, we choose the pair with the smallest worker index; if there are multiple ways to do that, we choose the pair with the smallest bike index). We repeat this process until there are no available workers. The Manhattan distance between two points p1 and p2 is Manhattan(p1, p2) = |p1.x - p2.x| + |p1.y - p2.y|. Return a vector ans of length N, where ans[i] is the index (0-indexed) of the bike that the i-th worker is assigned to. Example 1: (see image) Input: workers = [[0,0],[2,1]], bikes = [[1,2],[3,3]] Output: [1,0] Explanation: Worker 1 grabs Bike 0 as they are closest (without ties), and Worker 0 is assigned Bike 1. So the output is [1, 0].

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def fixedPoint(self, A): if A[0] > 0 or A[-1] < len(A) - 1: return -1 start = 0 end = len(A) - 1 first_pos = -1 while start <= end: mid = start + (end - start) / 2 if A[mid] == mid: first_pos = mid end = mid-1 elif A[mid] < mid: start = mid+1 else: end = mid-1 return first_pos if A[first_pos] == first_pos else -1

1064. Fixed Point Given an array A of distinct integers sorted in ascending order, return the smallest index i that satisfies A[i] == i. Return -1 if no such i exists. Example 1: Input: [-10,-5,0,3,7] Output: 3 Explanation: For the given array, A[0] = -10, A[1] = -5, A[2] = 0, A[3] = 3, thus the output is 3.

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def shortestPathBinaryMatrix(self, grid): if grid == [] or grid[0][0] == 1 or grid[-1][-1] == 1: return -1 m = len(grid) q = deque() q.append([0, 0, 1]) grid[0][0] = 1 while q: [x, y, step] = q.popleft() if x == m-1 and y == m-1: return step for x_ in range(max(0, x-1), min(m, x+2)): for y_ in range(max(0, y-1), min(m, y+2)): if grid[x_][y_] == 0: grid[x_][y_] = 1 q.append([x_, y_, step+1]) return -1

1091. Shortest Path in Binary Matrix In an N by N square grid, each cell is either empty (0) or blocked (1). A clear path from top-left to bottom-right has length k if and only if it is composed of cells C_1, C_2, ..., C_k such that: 1. Adjacent cells C_i and C_{i+1} are connected 8-directionally (ie., they are different and share an edge or corner) 2. C_1 is at location (0, 0) (ie. has value grid[0][0]) 3. C_k is at location (N-1, N-1) (ie. has value grid[N-1][N-1]) 4. If C_i is located at (r, c), then grid[r][c] is empty (ie. grid[r][c] == 0). Return the length of the shortest such clear path from top-left to bottom-right. If such a path does not exist, return -1. Example 1: Input: [[0,1],[1,0]] Output: 2

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def maximumMinimumPath(self, A): if A[0][0] == 0 or A[-1][-1] == 0: return 0 direction = [[0, 1], [1, 0], [-1, 0], [0, -1]] m, n = len(A), len(A[0]) visited = [[False]*n for _ in range(m)] heap = [] heapq.heapify(heap) heappush(heap, (-A[0][0], 0, 0)) visited[0][0] = True res = A[0][0] while len(heap) > 0: _, x, y = heappop(heap) res = min(res, A[x][y]) if x == m-1 and y == n-1: return res for d in direction: x_, y_ = x + d[0], y + d[1] if 0<=x_<m and 0<=y_<n and not visited[x_][y_]: visited[x_][y_] = True heappush(heap, (-A[x_][y_], x_, y_)) return -1

1102. Path With Maximum Minimum Value Given a matrix of integers A with R rows and C columns, find the maximum score of a path starting at [0,0] and ending at [R-1,C-1]. The score of a path is the minimum value in that path. For example, the value of the path 8 → 4 → 5 → 9 is 4. A path moves some number of times from one visited cell to any neighbouring unvisited cell in one of the 4 cardinal directions (north, east, west, south). Example 1: Input: [[5,4,5],[1,2,6],[7,4,6]] Output: 4 Explanation: The path with the maximum score is highlighted in yellow.

input: one Tree node output: a list of arrays test cases: Assumption: No Data Structure: No Algorithm: Backtracking Time complexity: O(N) Space complexity: O(N) class Solution(object): def __init__(self): self.res = [] def pathSum(self, root, sum): self.backtrack(root, sum, []) return self.res def backtrack(self, root, sum, path): if root is None: return path.append(root.val) if not root.left and not root.right and root.val == sum: self.res.append(list(path)) else: self.backtrack(root.left, sum-root.val, path) self.backtrack(root.right, sum-root.val, path) path.pop()

113. Path Sum II Given a binary tree and a sum, find all root-to-leaf paths where each path's sum equals the given sum.

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def longestCommonSubsequence(self, text1, text2): n = len(text1) m = len(text2) dp = [[0] * (m+1) for _ in range(n+1)] for i in range(1, n+1): for j in range(1, m+1): if text1[i-1] == text2[j-1]: dp[i][j] = 1 + dp[i-1][j-1] else: dp[i][j] = max(dp[i-1][j], dp[i][j-1]) return dp[n][m]

1143. Longest Common Subsequence Given two strings text1 and text2, return the length of their longest common subsequence. A subsequence of a string is a new string generated from the original string with some characters(can be none) deleted without changing the relative order of the remaining characters. (eg, "ace" is a subsequence of "abcde" while "aec" is not). A common subsequence of two strings is a subsequence that is common to both strings. If there is no common subsequence, return 0. Example 1: Input: text1 = "abcde", text2 = "ace" Output: 3 Explanation: The longest common subsequence is "ace" and its length is 3.

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def mostVisitedPattern(self, username, timestamp, website): record = defaultdict(list) for i, u in enumerate(username): record[u].append([timestamp[i], website[i]]) res = defaultdict(int) for u in record: record[u].sort() used = set() for i in range(len(record[u])): for j in range(i+1, len(record[u])): for k in range(j+1, len(record[u])): seq = record[u][i][1] + "+" + record[u][j][1] + "+" + record[u][k][1] if seq not in used: res[seq] += 1 used.add(seq) most_visted = max(res.values()) output = [] for s in res: if res[s] == most_visted: output.append(s.split("+")) output.sort() return output[0]

1152. Analyze User Website Visit Pattern We are given some website visits: the user with name username[i] visited the website website[i] at time timestamp[i]. A 3-sequence is a list of websites of length 3 sorted in ascending order by the time of their visits. (The websites in a 3-sequence are not necessarily distinct.) Find the 3-sequence visited by the largest number of users. If there is more than one solution, return the lexicographically smallest such 3-sequence. Input: username = ["joe","joe","joe","james","james","james","james","mary","mary","mary"], timestamp = [1,2,3,4,5,6,7,8,9,10], website = ["home","about","career","home","cart","maps","home","home","about","career"] Output: ["home","about","career"]

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def connectSticks(self, sticks): minheap = [] for s in sticks: heappush(minheap, s) res = 0 while len(minheap) > 1: cost = heappop(minheap) + heappop(minheap) res += cost heappush(minheap, cost) return res

1167. Minimum Cost to Connect Sticks You have some sticks with positive integer lengths. You can connect any two sticks of lengths X and Y into one stick by paying a cost of X + Y. You perform this action until there is one stick remaining. Return the minimum cost of connecting all the given sticks into one stick in this way. Example 1: Input: sticks = [2,4,3] Output: 14

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def minimumAbsDifference(self, arr): arr.sort() min_diff = float("inf") for i in range(1, len(arr)): if arr[i] - arr[i-1] < min_diff: min_diff = arr[i] - arr[i-1] res = [] res.append([arr[i-1], arr[i]]) elif (arr[i] - arr[i-1]) == min_diff: res.append([arr[i-1], arr[i]]) return res

1200. Minimum Absolute Difference Given an array of distinct integers arr, find all pairs of elements with the minimum absolute difference of any two elements. Return a list of pairs in ascending order(with respect to pairs), each pair [a, b] follows 1. a, b are from arr 2. a < b 3. b - a equals to the minimum absolute difference of any two elements in arr Example 1: Input: arr = [4,2,1,3] Output: [[1,2],[2,3],[3,4]] Explanation: The minimum absolute difference is 1. List all pairs with difference equal to 1 in ascending order.

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def closedIsland(self, grid): self.grid = grid self.m = len(grid) self.n = len(grid[0]) res = 0 for i in range(self.m): for j in range(self.n): if self.grid[i][j] == 1: continue self.closed = True self.dfs(i, j) if self.closed: res += 1 return res def dfs(self, x, y): if x < 0 or y < 0 or x >= self.m or y >= self.n or self.grid[x][y] == 1: return if x == 0 or y == 0 or x == (self.m-1) or y == (self.n-1): self.closed = False self.grid[x][y] = 1 direction = [[1, 0], [-1, 0], [0, 1], [0, -1]] for d in direction: self.dfs(x+d[0], y+d[1])

1254. Number of Closed Islands Given a 2D grid consists of 0s (land) and 1s (water). An island is a maximal 4-directionally connected group of 0s and a closed island is an island totally (all left, top, right, bottom) surrounded by 1s. Return the number of closed islands.

Data Structure: Algorithm: Time complexity: Space complexity: class Node: def __init__(self, isWord=False): self.isWord = isWord self.next = collections.defaultdict(Node) class Trie: def __init__(self): self.root = Node() def insert(self, word): cur = self.root for c in word: cur = cur.next[c] # here if not cur.isWord: cur.isWord = True def search(self, word): cur = self.root res = [] def dfs(cur, s, i): if not cur: return if i >= len(word) and cur.isWord: res.append(s) for t in cur.next.keys(): if i < len(word) and word[i] != t: continue dfs(cur.next[t], s + t, i + 1) dfs(cur, "", 0) return res class Solution: def suggestedProducts(self, products, searchWord): tree = Trie() for w in products: tree.insert(w) res = [] for i in range(1, len(searchWord) + 1): res.append(sorted(tree.search(searchWord[:i]))[:3]) return res

1268. Search Suggestions System Given an array of strings products and a string searchWord. We want to design a system that suggests at most three product names from products after each character of searchWord is typed. Suggested products should have common prefix with the searchWord. If there are more than three products with a common prefix return the three lexicographically minimums products. Return list of lists of the suggested products after each character of searchWord is typed. Input: products = ["mobile","mouse","moneypot","monitor","mousepad"], searchWord = "mouse" Output: [ ["mobile","moneypot","monitor"], ["mobile","moneypot","monitor"], ["mouse","mousepad"], ["mouse","mousepad"], ["mouse","mousepad"] ] Explanation: products sorted lexicographically = ["mobile","moneypot","monitor","mouse","mousepad"] After typing m and mo all products match and we show user ["mobile","moneypot","monitor"] After typing mou, mous and mouse the system suggests ["mouse","mousepad"]

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def xorOperation(self, n, start): array = [0] * n for i in range(n): array[i] = start + 2*i res = array[0] for i in range(1, n): res ^= array[i] return res

1486. XOR Operation in an Array Given an integer n and an integer start. Define an array nums where nums[i] = start + 2*i (0-indexed) and n == nums.length. Return the bitwise XOR of all elements of nums. Example 1: Input: n = 5, start = 0 Output: 8 Explanation: Array nums is equal to [0, 2, 4, 6, 8] where (0 ^ 2 ^ 4 ^ 6 ^ 8) = 8. Where "^" corresponds to bitwise XOR operator.

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def avoidFlood(self, rains): hashmap = {} dry_day = [] res = [1] * len(rains) for i, r in enumerate(rains): if r == 0: dry_day.append(i) continue res[i] = -1 if r not in hashmap: hashmap[r] = i else: found = False for d in dry_day: if d > hashmap[r]: res[d] = r dry_day.remove(d) hashmap[r] = i found = True break if not found: return [] return res

1488. Avoid Flood in The City Your country has an infinite number of lakes. Initially, all the lakes are empty, but when it rains over the nth lake, the nth lake becomes full of water. If it rains over a lake which is full of water, there will be a flood. Your goal is to avoid the flood in any lake. Given an integer array rains where: 1. rains[i] > 0 means there will be rains over the rains[i] lake. 2. rains[i] == 0 means there are no rains this day and you can choose one lake this day and dry it. Return an array ans where: 1. ans.length == rains.length 2. ans[i] == -1 if rains[i] > 0. 3. ans[i] is the lake you choose to dry in the ith day if rains[i] == 0. If there are multiple valid answers return any of them. If it is impossible to avoid flood return an empty array. Notice that if you chose to dry a full lake, it becomes empty, but if you chose to dry an empty lake, nothing changes. (see example 4) Example 1: Input: rains = [1,2,3,4] Output: [-1,-1,-1,-1] Example 4: Input: rains = [69,0,0,0,69] Output: [-1,69,1,1,-1] Explanation: Any solution on one of the forms [-1,69,x,y,-1], [-1,x,69,y,-1] or [-1,x,y,69,-1] is acceptable where 1 <= x,y <= 10^9

input: one string output: one integer test cases: "3+2*2" => 7 Assumption: No Data Structure: No one stack: record all nums one string: record the previous operator Algorithm: Time complexity: O(n) Space complexity: O(n) class Solution(object): def calculate(self, s): res = 0 stack = [] pre_op = '+' num = 0 for i, c in enumerate(s): if c in '0123456789': num = 10*num + int(c) if c in '+-*/' or i == (len(s) - 1): if pre_op == '+': stack.append(num) if pre_op == '-': stack.append(-num) if pre_op == '*': pre_num = stack.pop() stack.append(pre_num * num) if pre_op == '/': pre_num = stack.pop() res = abs(pre_num) // abs(num) if pre_num < 0: stack.append(-res) else: stack.append(res) pre_op = c num = 0 return sum(stack)

227. Basic Calculator II Implement a basic calculator to evaluate a simple expression string. The expression string contains only non-negative integers, +, -, *, / operators and empty spaces . The integer division should truncate toward zero.

class Solution(object): def majorityElement(self, nums): counts = collections.Counter(nums) res = [] for n, t in counts.items(): if (t > len(nums)/3): res.append(n) return res

229. Majority Element II Given an integer array of size n, find all elements that appear more than ⌊ n/3 ⌋ times.

input: output: test cases: Assumption: No Data Structure: two stack Algorithm: pop and peak: if stack2 is empty, pop every element in stack1 and push to stack2. Pop stack2 Time complexity: O(n) Space complexity: O(n) class MyQueue(object): def __init__(self): self.stack1 = [] self.stack2 = [] def push(self, x): self.stack1.append(x) def pop(self): if self.stack2 == []: while self.stack1 != []: self.stack2.append(self.stack1[-1]) self.stack1.pop() return self.stack2.pop() def peek(self): if self.stack2 == []: while self.stack1 != []: self.stack2.append(self.stack1[-1]) self.stack1.pop() return self.stack2[-1] def empty(self): return self.stack1 == [] and self.stack2 == []

232. Implement Queue using Stacks Implement the following operations of a queue using stacks. push(x) -- Push element x to the back of queue. pop() -- Removes the element from in front of queue. peek() -- Get the front element. empty() -- Return whether the queue is empty.

input: output: test cases: Assumption: No Data Structure: No Algorithm: Swap with Next Node Time complexity: O(1) Space complexity: O(1) class Solution(object): def deleteNode(self, node): node.val = node.next.val node.next = node.next.next

237. Delete Node in a Linked List Write a function to delete a node (except the tail) in a singly linked list, given only access to that node. Given linked list -- head = [4,5,1,9], which looks like following:

input: one array output: one array test cases: [1,2,3,4] => [24,12,8,6] Assumption: No Data Structure: One array L[i] represents product of all the elements to the left of element at index i. One array R[i] represents product of all the elements to the right of element at index i. Algorithm: Left and Right product lists product except self as L[i] * R[i] Time complexity: O(N) Space complexity: O(N) class Solution(object): def productExceptSelf(self, nums): left = [1] * len(nums) right = [1] * len(nums) for i in range(0, len(nums)-1): left[i+1] = left[i] * nums[i] for i in range(len(nums)-1, 0, -1): right[i-1] = right[i] * nums[i] res = [] for i in range(len(nums)): res.append(left[i]*right[i]) return res

238. Product of Array Except Self Given an array nums of n integers where n > 1, return an array output such that output[i] is equal to the product of all the elements of nums except nums[i]

input: one array output: one array test cases: nums = [1,3,-1,-3,5,3,6,7], and k = 3 => [3,3,5,5,6,7] Assumption: No Data Structure: deque: store the largest element in the window Algorithm: Monotonic decreasing Deque pop the last element if the incoming number is larger than the last element. pop the first element if the queue length is larger than k append the first element to result Time complexity: O(N) Space complexity: O(N) class Solution(object): def maxSlidingWindow(self, nums, k): q = deque() res = [] for i, n in enumerate(nums): while q and nums[i] >= nums[q[-1]]: q.pop() q.append(i) if (i - q[0]) == k: q.popleft() if i >= (k - 1): res.append(nums[q[0]]) return res

239. Sliding Window Maximum Given an array nums, there is a sliding window of size k which is moving from the very left of the array to the very right. You can only see the k numbers in the window. Each time the sliding window moves right by one position. Return the max sliding window.

input: one matrix output: True or False test cases: [ [1, 4, 7, 11, 15], [2, 5, 8, 12, 19], [3, 6, 9, 16, 22], [10, 13, 14, 17, 24], [18, 21, 23, 26, 30] ] Assumption: No Data Structure: No Algorithm: Search Space Reduction initialize a (row, col) pointer to the top-right of the matrix if the currently-pointed-to value is larger than target we can move one column "left". if the currently-pointed-to value is smaller than target, we can move one row "down". Time complexity: O(N) Space complexity: O(1) class Solution(object): def searchMatrix(self, matrix, target): if not matrix or len(matrix) == 0 or len(matrix[0]) == 0: return False i, j = 0, len(matrix[0]) - 1 while 0<=i<len(matrix) and 0<=j<len(matrix[0]): if target == matrix[i][j]: return True if target > matrix[i][j]: i+=1 else: j -= 1 return False

240. Search a 2D Matrix II Write an efficient algorithm that searches for a value in an m x n matrix. This matrix has the following properties: Integers in each row are sorted in ascending from left to right. Integers in each column are sorted in ascending from top to bottom.

input: one list of strings output: one integer test cases: ["practice", "makes", "perfect", "coding", "makes"] Input: word1 = "coding", word2 = "practice" Output: 3 Assumption: No Data Structure: No Algorithm: One pass keeping two indices i1 and i2 where we store the most recent locations of word1 and word2. Each time we find a new occurrence of one of the words, we do not need to search the entire array for the other word, since we already have the index of its most recent occurrence. Time complexity: O(N) Space complexity: O(1) class Solution(object): def shortestDistance(self, words, word1, word2): p1 = None p2 = None res = float("inf") for i, word in enumerate(words): if word == word1: p1 = i if word == word2: p2 = i if p1 != None and p2 != None and abs(p1-p2) < res: res = abs(p1-p2) return res

243. Shortest Word Distance Given a list of words and two words word1 and word2, return the shortest distance between these two words in the list.

Time complexity: O(N) Space complexity: O(1) class WordDistance(object): def __init__(self, words): self.words = dict() for i, w in enumerate(words): if w not in self.words: self.words[w] = [i] else: self.words[w].append(i) def shortest(self, word1, word2): res = float("inf") w1 = self.words[word1] w2 = self.words[word2] i, j = 0, 0 while i < len(w1) and j < len(w2): p1 = w1[i] p2 = w2[j] if p1 < p2: res = min(res, abs(p2-p1)) i += 1 else: res = min(res, abs(p2-p1)) j += 1 return res

244. Shortest Word Distance II Design a class which receives a list of words in the constructor, and implements a method that takes two words word1 and word2 and return the shortest distance between these two words in the list. Your method will be called repeatedly many times with different parameters. Example:Assume that words = ["practice", "makes", "perfect", "coding", "makes"]. Input: word1 = "coding", word2 = "practice" Output: 3 Input: word1 = "makes", word2 = "coding" Output: 1

test cases: words = ["practice", "makes", "perfect", "coding", "makes"] word1 = "makes", word2 = "coding" => 1 Assumption: No Data Structure: hashmap: store all the locations of word1 and word2 Algorithm: one pass find the closest index in hashmap[word1] and hashmap[word2] class Solution(object): def shortestWordDistance(self, words, word1, word2): vol = collections.defaultdict(list) for i, w in enumerate(words): vol[w].append(i) w1 = vol[word1] w2 = vol[word2] i = 0 j = 0 res = float("inf") while i < len(w1) and j < len(w2): p1, p2 = w1[i], w2[j] if p1 < p2: res = min(res, abs(p1-p2)) i += 1 elif p1 > p2: res = min(res, abs(p1-p2)) j += 1 else: i += 1 return res

245. Shortest Word Distance III Given a list of words and two words word1 and word2, return the shortest distance between these two words in the list. word1 and word2 may be the same and they represent two individual words in the list.

input: one Tree node output: one integer test cases: root = [5,1,5,5,5,null,5] => 4 Assumption: No Data Structure: No Algorithm: DFS Given a node in our tree, we know that it is a univalue subtree if it meets one of the following criteria: The node has no children (base case) All of the node's children are univalue subtrees, and the node and its children all have the same value Time complexity: O(N) Space complexity: O(1) class Solution(object): def countUnivalSubtrees(self, root): if (root == None): return 0 self.res = 0 self.dfs(root) return self.res def dfs(self, node): if node.left is None and node.right is None: self.res += 1 return True is_uni = True if node.left is not None: is_uni = self.dfs(node.left) and is_uni and (node.left.val == node.val) if node.right is not None: is_uni = self.dfs(node.right) and is_uni and (node.right.val == node.val) if is_uni: self.res += 1 return is_uni

250. Count Univalue Subtrees Given a binary tree, count the number of uni-value subtrees. A Uni-value subtree means all nodes of the subtree have the same value.

input: one Tree node output: one integer test cases: root = [5,1,5,5,5,null,5] => 4 Assumption: No Data Structure: minheap: record the end time of each meeting Algorithm: for a meeting, check the earliest end time of the current meetings. if no meeting ends before the start to the current meeting, append else, heapreplace() The node has no children (base case) All of the node's children are univalue subtrees, and the node and its children all have the same value Time complexity: O(N log N) Space complexity: O(N) class Solution(object): def minMeetingRooms(self, intervals): intervals.sort(key = lambda x: x[0]) minheap = [] for start, end in intervals: if minheap and start >= minheap[0]: heapreplace(minheap, end) else: heappush(minheap, end) return len(minheap)

253. Meeting Rooms II Given an array of meeting time intervals consisting of start and end times [[s1,e1],[s2,e2],...] (si < ei), find the minimum number of conference rooms required.

input: one matrix output: one integer test cases: Assumption: No Data Structure: one 2-D array DP[i][j]: total cost for house i with color j Algorithm: Dynamic Programming Transition Function: res[i][j] += min(res[i-1][(j+1)%3], res[i-1][(j+2)%3]) Base Case: DP[0][j] = costs[0][j] Time complexity: O(N) Space complexity: O(1) class Solution(object): def minCost(self, costs): if len(costs) == 0: return 0 res = costs[:] for i in range(1, len(costs)): for j in range(3): res[i][j] += min(res[i-1][(j+1)%3], res[i-1][(j+2)%3]) return min(res[-1])

256. Paint House There are a row of n houses, each house can be painted with one of the three colors: red, blue or green. The cost of painting each house with a certain color is different. You have to paint all the houses such that no two adjacent houses have the same color. The cost of painting each house with a certain color is represented by a n x 3 cost matrix. For example, costs[0][0] is the cost of painting house 0 with color red; costs[1][2] is the cost of painting house 1 with color green, and so on... Find the minimum cost to paint all houses.

input: one matrix output: one integer test cases: Assumption: No Data Structure: one 2-D array DP[i][j]: total cost for house i with color j Algorithm: DFS Use left and right is None as end condition Time complexity: O(N) Space complexity: O(1) class Solution(object): def binaryTreePaths(self, root): if not root: return [] self.all_path = [] self.dfs(root, '') return self.all_path def dfs(self, root, path): if path == '': path = str(root.val) else: path += '->' + str(root.val) if root.left is None and root.right is None: self.all_path.append(path) return if root.left: self.dfs(root.left, path) if root.right: self.dfs(root.right, path)

257. Binary Tree Paths Given a binary tree, return all root-to-leaf paths.

input: one array, one target output: one integer test cases: Assumption: No Data Structure: one 2-D array DP[i][j]: total cost for house i with color j Algorithm: Two pointers Use two pointers to find 2sum smaller Iterate all the values in the array Time complexity: O(N) Space complexity: O(1) class Solution(object): def threeSumSmaller(self, nums, target): res = 0 nums.sort() for i in range(len(nums)): res += self.twoSumSmaller(nums, i+1, target-nums[i]) return res def twoSumSmaller(self, nums, start, target): res = 0 p1 = start p2 = len(nums) - 1 while p1 < p2: if (nums[p1] + nums[p2]) < target: res += p2-p1 p1 += 1 else: p2 -= 1 return res

259. 3Sum Smaller Given an array of n integers nums and a target, find the number of index triplets i, j, k with 0 <= i < j < k < n that satisfy the condition nums[i] + nums[j] + nums[k] < target.

input: one matrix output: one integer test cases: Assumption: No Data Structure: one 2-D array DP[i][j]: total cost for house i with color j Algorithm: Dynamic Programming Transition Function: DP[i][j] = cost[i][j] + min(DP[i-1][k]) for k != j Base Case: DP[0][j] = costs[0][j] Time complexity: O(N) Space complexity: O(1) class Solution(object): def minCostII(self, costs): if not costs: return 0 DP = costs[:] n = len(costs) k = len(costs[0]) for i in range(1, n): for j in range(k): res = float("inf") for h in range(1, k): res = min(res, DP[i-1][(j+h)%k]) DP[i][j] += res return min(DP[n-1][:])

265. Paint House II There are a row of n houses, each house can be painted with one of the k colors. The cost of painting each house with a certain color is different. You have to paint all the houses such that no two adjacent houses have the same color. The cost of painting each house with a certain color is represented by a n x k cost matrix. For example, costs[0][0] is the cost of painting house 0 with color 0; costs[1][2] is the cost of painting house 1 with color 2, and so on... Find the minimum cost to paint all houses.

input: one matrix output: one integer test cases: Assumption: No Data Structure: Algorithm: Keep placing the element to the right index if cannot place, move to the next element Finally, check if element matches with the index Time complexity: O(N) Space complexity: O(1) class Solution(object): def missingNumber(self, nums): i = 0 while i < len(nums): j = nums[i] if j < len(nums) and nums[i] != nums[j]: nums[i], nums[j] = nums[j], nums[i] else: i += 1 for i in range(len(nums)): if i != nums[i]: return i return len(nums)

268. Missing Number Given an array containing n distinct numbers taken from 0, 1, 2, ..., n, find the one that is missing from the array.

input: one array of strings output: one string test cases: Assumption: Data Structure: One hashmap: to represent the graph One hashmap: to record the in-degree of each node Algorithm: Topological Sort to find a global order for all nodes in a DAG (Directed Acyclic Graph) with regarding to their dependencies. Time complexity: O(V + E) Space complexity: O(V + E) class Solution(object): def alienOrder(self, words): hashmap_graph = defaultdict(set) hashmap_degree = Counter({c: 0 for word in words for c in word}) for w1, w2 in zip (words, words[1:]): for c, d in zip(w1, w2): if c != d: if d not in hashmap_graph[c]: hashmap_graph[c].add(d) hashmap_degree[d] += 1 break elif len(w2) < len(w1) and len(words) == 2: return "" q = deque([node for node in hashmap_degree if hashmap_degree[node] == 0]) res = [] while q: node = q.popleft() res.append(node) for next_node in hashmap_graph[node]: hashmap_degree[next_node] -= 1 if hashmap_degree[next_node] == 0: q.append(next_node) if len(hashmap_degree) == len(res): return ''.join(res) return ''

269. Alien Dictionary There is a new alien language which uses the latin alphabet. However, the order among letters are unknown to you. You receive a list of non-empty words from the dictionary, where words are sorted lexicographically by the rules of this new language. Derive the order of letters in this language.

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def hundredToWords(self, num): res = '' wordUnder20 = ['', 'One', 'Two', 'Three', 'Four', 'Five', 'Six', 'Seven', 'Eight', 'Nine',\ 'Ten', 'Eleven', 'Twelve', 'Thirteen', 'Fourteen', 'Fifteen', 'Sixteen', 'Seventeen', 'Eighteen', 'Nineteen'] wordOver20 = ['', '', 'Twenty', 'Thirty', 'Forty', 'Fifty', 'Sixty', 'Seventy', 'Eighty', 'Ninety'] if (num//100) > 0: res += ' ' + wordUnder20[num // 100] + ' Hundred' num = num%100 if num < 20: res += ' ' + wordUnder20[num] else: res += ' ' + wordOver20[num//10] + ' ' + wordUnder20[num%10] return strip(res) def numberToWords(self, num): if num == 0: return 'Zero' wordBit = {0: '', 3: 'Thousand', 6: 'Million', 9: 'Billion'} return strip(self.buildWords(num, 0, wordBit)) def buildWords(self, num, bit, wordBit): if num == 0: return '' if num%1000 > 0: res = ' ' + self.hundredToWords(num%1000) + ' ' + wordBit[bit] else: res = '' return self.buildWords(num//(1000), bit+3, wordBit) + res

273. Integer to English Words Convert a non-negative integer to its english words representation. Given input is guaranteed to be less than 231 - 1. Example 1: Input: 123 Output: "One Hundred Twenty Three" Example 2: Input: 12345 Output: "Twelve Thousand Three Hundred Forty Five" Example 3: Input: 1234567 Output: "One Million Two Hundred Thirty Four Thousand Five Hundred Sixty Seven" Example 4: Input: 1234567891 Output: "One Billion Two Hundred Thirty Four Million Five Hundred Sixty Seven Thousand Eight Hundred Ninety One"

input: one array of strings output: one string test cases: Assumption: Data Structure: Algorithm: Think geometrically. Imagine plotting a histogram where the y-axis represents the number of citations for each paper. After sorting in descending order, h-index is the length of the largest square in the histogram. Time complexity: O(nlogn) Space complexity: O(1) class Solution(object): def hIndex(self, citations): res = 0 citations.sort() for i, n in enumerate(citations[::-1]): if n >= (i+1): res = i+1 else: break return res

274. H-Index Given an array of citations (each citation is a non-negative integer) of a researcher, write a function to compute the researcher's h-index. According to the definition of h-index on Wikipedia: "A scientist has index h if h of his/her N papers have at least h citations each, and the other N − h papers have no more than h citations each." Example: Input: citations = [3,0,6,1,5] Output: 3 Explanation: [3,0,6,1,5] means the researcher has 5 papers in total and each of them had received 3, 0, 6, 1, 5 citations respectively. Since the researcher has 3 papers with at least 3 citations each and the remaining two with no more than 3 citations each, her h-index is 3.

class Solution(object): def hIndex(self, citations): if citations == []: return 0 start = 0 end = len(citations) while (start+1<end): mid = start + (end-start)/2 if citations[mid] < (len(citations)-mid): start = mid else: end = mid if citations[start] >= (len(citations)-start): return len(citations)-start return len(citations)-end

275. H-Index II Given an array of citations sorted in ascending order (each citation is a non-negative integer) of a researcher, write a function to compute the researcher's h-index. According to the definition of h-index on Wikipedia: "A scientist has index h if h of his/her N papers have at least h citations each, and the other N − h papers have no more than h citations each." Example: Input: citations = [0,1,3,5,6] Output: 3 Explanation: [0,1,3,5,6] means the researcher has 5 papers in total and each of them had received 0, 1, 3, 5, 6 citations respectively. Since the researcher has 3 papers with at least 3 citations each and the remaining two with no more than 3 citations each, her h-index is 3.

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def findCelebrity(self, n): res = [True] * n for i in range(n): for j in range(n): if j != i: if knows(i, j) or not knows(j, i): res[i] = False break return res.index(True) if any(res) else -1

277. Find the Celebrity Suppose you are at a party with n people (labeled from 0 to n - 1) and among them, there may exist one celebrity. The definition of a celebrity is that all the other n - 1 people know him/her but he/she does not know any of them. Now you want to find out who the celebrity is or verify that there is not one. The only thing you are allowed to do is to ask questions like: "Hi, A. Do you know B?" to get information of whether A knows B. You need to find out the celebrity (or verify there is not one) by asking as few questions as possible (in the asymptotic sense). You are given a helper function bool knows(a, b) which tells you whether A knows B. Implement a function int findCelebrity(n). There will be exactly one celebrity if he/she is in the party. Return the celebrity's label if there is a celebrity in the party. If there is no celebrity, return -1. Example 1: Input: graph = [ [1,1,0], [0,1,0], [1,1,1] ] Output: 1 Explanation: There are three persons labeled with 0, 1 and 2. graph[i][j] = 1 means person i knows person j, otherwise graph[i][j] = 0 means person i does not know person j. The celebrity is the person labeled as 1 because both 0 and 2 know him but 1 does not know anybody.

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def firstBadVersion(self, n): start = 1 end = n left_bond = -1 while start <= end: mid = start + (end-start)//2 if isBadVersion(mid): left_bond = mid end = mid - 1 else: start = mid + 1 return left_bond

278. First Bad Version 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. 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. You are given an API bool isBadVersion(version) which will return whether version is bad. Implement a function to find the first bad version. You should minimize the number of calls to the API. Example: Given n = 5, and version = 4 is the first bad version. call isBadVersion(3) -> false call isBadVersion(5) -> true call isBadVersion(4) -> true Then 4 is the first bad version.

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def numSquares(self, n): DP = [0] * (n+1) for i in range(1, n+1): DP[i] = float('inf') j = 1 while (j**2 <= i): DP[i] = min(DP[i], DP[i-j**2]+1) j+=1 return DP[n]

279. Perfect Squares Given a positive integer n, find the least number of perfect square numbers (for example, 1, 4, 9, 16, ...) which sum to n. Example 1: Input: n = 12 Output: 3 Explanation: 12 = 4 + 4 + 4. Example 2: Input: n = 13 Output: 2 Explanation: 13 = 4 + 9.

Data Structure: Algorithm: Time complexity: Space complexity: # Below is the interface for Iterator, which is already defined for you. # # class Iterator(object): # def __init__(self, nums): # """ # Initializes an iterator object to the beginning of a list. # :type nums: List[int] # """ # # def hasNext(self): # """ # Returns true if the iteration has more elements. # :rtype: bool # """ # # def next(self): # """ # Returns the next element in the iteration. # :rtype: int # """ class PeekingIterator(object): def __init__(self, iterator): self.iterator = iterator self.n = None def peek(self): if self.n == None: self.n = self.iterator.next() return self.n def next(self): if self.n != None: tmp = self.n self.n = None return tmp else: return self.iterator.next() def hasNext(self): if self.n != None: return True else: return self.iterator.hasNext() # Your PeekingIterator object will be instantiated and called as such: # iter = PeekingIterator(Iterator(nums)) # while iter.hasNext(): # val = iter.peek() # Get the next element but not advance the iterator. # iter.next() # Should return the same value as [val].

284. Peeking Iterator Given an Iterator class interface with methods: next() and hasNext(), design and implement a PeekingIterator that support the peek() operation -- it essentially peek() at the element that will be returned by the next call to next(). Example: Assume that the iterator is initialized to the beginning of the list: [1,2,3]. Call next() gets you 1, the first element in the list. Now you call peek() and it returns 2, the next element. Calling next() after that still return 2. You call next() the final time and it returns 3, the last element. Calling hasNext() after that should return false.

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def findDuplicate(self, nums): i = 0 while i < len(nums): if nums[i] != i + 1: if nums[nums[i] - 1] == nums[i]: return nums[i] nums[nums[i] - 1], nums[i] = nums[i], nums[nums[i] - 1] else: i += 1 return -1

287. Find the Duplicate Number Given an array nums containing n + 1 integers where each integer is between 1 and n (inclusive), prove that at least one duplicate number must exist. Assume that there is only one duplicate number, find the duplicate one. Example 1: Input: [1,3,4,2,2] Output: 2 Example 2: Input: [3,1,3,4,2] Output: 3

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def gameOfLife(self, board): m = len(board) n = len(board[0]) res = [[0]*n for _ in range(m)] for i in range(m): for j in range(n): num_neighbors = self.countNeighbors(i, j , board) if board[i][j] == 1: if num_neighbors < 2 or num_neighbors > 3: res[i][j] == 0 else: res[i][j] = 1 else: if num_neighbors == 3: res[i][j] = 1 for i in range(m): for j in range(n): board[i][j] = res[i][j] def countNeighbors(self, x, y, board): direction = [[1, 0], [-1, 0], [0, 1], [0, -1], [1, 1], [1, -1], [-1, 1], [-1, -1]] res = 0 for d in direction: i, j = x + d[0], y + d[1] if 0<=i<len(board) and 0<=j<len(board[0]) and board[i][j] == 1: res += 1 return res

289. Game of Life According to the Wikipedia's article: "The Game of Life, also known simply as Life, is a cellular automaton devised by the British mathematician John Horton Conway in 1970." Given a board with m by n cells, each cell has an initial state live (1) or dead (0). Each cell interacts with its eight neighbors (horizontal, vertical, diagonal) using the following four rules (taken from the above Wikipedia article): 1. Any live cell with fewer than two live neighbors dies, as if caused by under-population. 2. Any live cell with two or three live neighbors lives on to the next generation. 3. Any live cell with more than three live neighbors dies, as if by over-population.. Any dead cell with exactly three live neighbors becomes a live cell, as if by reproduction. Write a function to compute the next state (after one update) of the board given its current state. The next state is created by applying the above rules simultaneously to every cell in the current state, where births and deaths occur simultaneously. Example: Input: [ [0,1,0], [0,0,1], [1,1,1], [0,0,0] ] Output: [ [0,0,0], [1,0,1], [0,1,1], [0,1,0] ]

Data Structure: Algorithm: Time complexity: Space complexity: class MedianFinder(object): def __init__(self): self.minheap = [] self.maxheap = [] def addNum(self, num): if not self.maxheap or -num >= self.maxheap[0]: heappush(self.maxheap, -num) else: heappush(self.minheap, num) if len(self.maxheap) > len(self.minheap) + 1: heappush(self.minheap, -heappop(self.maxheap)) elif len(self.maxheap) < len(self.minheap): heappush(self.maxheap, -heappop(self.minheap)) def findMedian(self): """ :rtype: float """ if len(self.maxheap) == len(self.minheap): return -self.maxheap[0]/2.0 + self.minheap[0]/2.0 else: return -self.maxheap[0]

295. Find Median from Data Stream Median is the middle value in an ordered integer list. If the size of the list is even, there is no middle value. So the median is the mean of the two middle value. For example, [2,3,4], the median is 3 [2,3], the median is (2 + 3) / 2 = 2.5 Design a data structure that supports the following two operations: void addNum(int num) - Add a integer number from the data stream to the data structure. double findMedian() - Return the median of all elements so far.

Data Structure: Algorithm: Time complexity: Space complexity: class Codec: def notNone(self, q): for p in q: if p: return True return False def num2str(self, num): res = '[' for n in num: if n or n == 0: res += str(n) + ',' else: res +='null,' res = res[0:-1] +']' return res def str2num(self, num_str): num = [] for s in num_str[1:-1].split(','): if s == 'null': num.append(None) else: num.append(int(s)) return num def serialize(self, root): """Encodes a tree to a single string. :type root: TreeNode :rtype: str """ if not root: return [] q = deque() q.append(root) res = [] while self.notNone(q): curr_level = len(q) for i in range(curr_level): node = q.popleft() if node: res.append(node.val) q.append(node.left) q.append(node.right) else: res.append(None) return self.num2str(res) def deserialize(self, data): """Decodes your encoded data to tree. :type data: str :rtype: TreeNode """ if data == []: return [] data = self.str2num(data) root = TreeNode(data[0]) q = deque() q.append(root) i = 1 while q: node = q.popleft() if i < len(data) and data[i] != None: left = TreeNode(data[i]) node.left = left q.append(left) if (i+1) < len(data) and data[i+1] != None: right = TreeNode(data[i+1]) node.right = right q.append(right) i += 2 return root

297. Serialize and Deserialize Binary Tree Serialization is the process of converting a data structure or object into a sequence of bits so that it can be stored in a file or memory buffer, or transmitted across a network connection link to be reconstructed later in the same or another computer environment. Design an algorithm to serialize and deserialize a binary tree. There is no restriction on how your serialization/deserialization algorithm should work. You just need to ensure that a binary tree can be serialized to a string and this string can be deserialized to the original tree structure. Example: You may serialize the following tree: 1 / \ 2 3 / \ 4 5 as "[1,2,3,null,null,4,5]"

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def longestConsecutive(self, root): self.max = 0 self.dfs(root, None, 0) return self.max def dfs(self, node, val, length): if node == None: return if val == None or node.val == (val+1): length += 1 self.max = max(self.max, length) else: length = 1 if node.left: self.dfs(node.left, node.val, length) if node.right: self.dfs(node.right, node.val, length)

298. Binary Tree Longest Consecutive Sequence Given a binary tree, find the length of the longest consecutive sequence path. The path refers to any sequence of nodes from some starting node to any node in the tree along the parent-child connections. The longest consecutive path need to be from parent to child (cannot be the reverse).

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def getHint(self, secret, guess): bulls = 0 cows = 0 secret_dict = collections.defaultdict(int) for (s, g) in zip(secret, guess): if (s == g): bulls+=1 else: secret_dict[s] += 1 for (i, g) in enumerate(guess): if secret[i] != g and secret_dict[g]: cows += 1 secret_dict[g] -= 1 return str(bulls)+'A'+str(cows)+'B';

299. Bulls and Cows You are playing the following Bulls and Cows game with your friend: You write down a number and ask your friend to guess what the number is. Each time your friend makes a guess, you provide a hint that indicates how many digits in said guess match your secret number exactly in both digit and position (called "bulls") and how many digits match the secret number but locate in the wrong position (called "cows"). Your friend will use successive guesses and hints to eventually derive the secret number. Write a function to return a hint according to the secret number and friend's guess, use A to indicate the bulls and B to indicate the cows. Please note that both secret number and friend's guess may contain duplicate digits.

Data Structure: one 1-D array to store the root Algorithm: Union Find/Disjoint Set Time complexity: Space complexity: class Solution(object): def numIslands2(self, m, n, positions): root = [-1] * (m*n) cnt = 0 res = [] direction = [[1, 0], [-1, 0], [0, 1], [0, -1]] for pos in positions: i = pos[0]*n + pos[1] if root[i] != -1: res.append(cnt) continue cnt += 1 root[i] = i for d in direction: x, y = pos[0] + d[0], pos[1] + d[1] j = x*n + y if 0<=x<m and 0<=y<n and root[j] != -1: p, q = self.findRoot(i, root), self.findRoot(j, root) if p != q: root[p] = self.findRoot(j, root) cnt -= 1 res.append(cnt) return res def findRoot(self, i, root): if root[i] == i: return i return self.findRoot(root[i], root)

305. Number of Islands II A 2d grid map of m rows and n columns is initially filled with water. We may perform an addLand operation which turns the water at position (row, col) into a land. Given a list of positions to operate, count the number of islands after each addLand operation. An island is surrounded by water and is formed by connecting adjacent lands horizontally or vertically. You may assume all four edges of the grid are all surrounded by water. Example: Input: m = 3, n = 3, positions = [[0,0], [0,1], [1,2], [2,1]] Output: [1,1,2,3]

Data Structure: Algorithm: Time complexity: Space complexity: class NumArray(object): def __init__(self, nums): self.n = len(nums) self.seg_tree = self.buildTree(nums) def buildTree(self, nums): res = [0] * (2* self.n) for i in range(self.n, 2* self.n): res[i] = nums[i- self.n] for i in range(self.n-1, -1, -1): res[i] = res[i*2] + res[i*2+1] return res def update(self, i, val): self.seg_tree[i+ self.n] = val curr = i+self.n while curr > 0: if curr%2 == 0: left = curr right = curr+1 else: left = curr-1 right = curr self.seg_tree[curr/2] = self.seg_tree[left] + self.seg_tree[right] curr /= 2 def sumRange(self, i, j): l, r = i+self.n, j+self.n res = 0 while l <= r: if l%2 == 1: res += self.seg_tree[l] l+=1 if r%2 == 0: res += self.seg_tree[r] r-=1 l /= 2 r /= 2 return res

307. Range Sum Query - Mutable Given an integer array nums, find the sum of the elements between indices i and j (i ≤ j), inclusive. The update(i, val) function modifies nums by updating the element at index i to val.

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def maxProfit(self, prices): n = len(prices) dp = [[0] * 2 for _ in range(n+1)] dp[0][0] = 0 dp[0][1] = -float('inf') for i in range(1, n+1): dp[i][0] = max(dp[i-1][0], dp[i-1][1] + prices[i-1]) dp[i][1] = max(dp[i-1][1], dp[i-2][0] - prices[i-1]) return dp[n][0]

309. Best Time to Buy and Sell Stock with Cooldown Say you have an array for which the ith element is the price of a given stock on day i. Design an algorithm to find the maximum profit. You may complete as many transactions as you like (ie, buy one and sell one share of the stock multiple times) with the following restrictions: You may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again). After you sell your stock, you cannot buy stock on next day. (ie, cooldown 1 day) Input: [1,2,3,0,2] Output: 3 Explanation: transactions = [buy, sell, cooldown, buy, sell]

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def coinChange(self, coins, amount): dp = [0] * (amount + 1) for i in range(1, amount+1): res = float('inf') for c in coins: if c > i: continue res = min(res, 1 + dp[i-c]) dp[i] = res return dp[amount] if dp[amount] != float('inf') else -1

322. Coin Change You are given coins of different denominations and a total amount of money amount. Write a function to compute the fewest number of coins that you need to make up that amount. If that amount of money cannot be made up by any combination of the coins, return -1. Example 1: Input: coins = [1, 2, 5], amount = 11 Output: 3 Explanation: 11 = 5 + 5 + 1 Example 2: Input: coins = [2], amount = 3 Output: -1

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def oddEvenList(self, head): if head is None or head.next is None or head.next.next is None: return head odd = head even = head.next even_head = head.next curr = head.next.next i = 3 while curr: temp = curr.next if i%2 == 1: odd.next = curr odd = odd.next else: even.next = curr even = even.next curr = temp i += 1 even.next = None odd.next = even_head return head

328. Odd Even Linked List Given a singly linked list, group all odd nodes together followed by the even nodes. Please note here we are talking about the node number and not the value in the nodes. You should try to do it in place. The program should run in O(1) space complexity and O(nodes) time complexity.

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def __init__(self): self.memo = {} def rob(self, root): if root == None: return 0 if root in self.memo: return self.memo[root] is_rob = root.val if root.left: is_rob += self.rob(root.left.left) + self.rob(root.left.right) if root.right: is_rob += self.rob(root.right.left) + self.rob(root.right.right) not_rob = self.rob(root.left) + self.rob(root.right) res = max(is_rob, not_rob) self.memo[root] = res return res

337. House Robber III The thief has found himself a new place for his thievery again. There is only one entrance to this area, called the "root." Besides the root, each house has one and only one parent house. After a tour, the smart thief realized that "all houses in this place forms a binary tree". It will automatically contact the police if two directly-linked houses were broken into on the same night. Determine the maximum amount of money the thief can rob tonight without alerting the police.

test case: s = "eceba", k = 2 => 3 Data Structure: hashtable: store the counts of characters in the window Algorithm: Sliding window Shrink the window when there are more than k characters. Time complexity: O(n) Space complexity: O(n) class Solution(object): def lengthOfLongestSubstringKDistinct(self, s, k): start, res = 0, 0 hash_map = {} for end in range(len(s)): if s[end] not in hash_map: hash_map[s[end]] = 1 else: hash_map[s[end]] += 1 while len(hash_map) > k: hash_map[s[start]] -= 1 if hash_map[s[start]] == 0: del hash_map[s[start]] start += 1 res = max(res, end - start + 1) return res

340. Longest Substring with At Most K Distinct Characters Given a string, find the length of the longest substring T that contains at most k distinct characters. Input: s = "eceba", k = 2 Output: 3 Explanation: T is "ece" which its length is 3.

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def topKFrequent(self, nums, k): hash_map = {} for n in nums: if n not in hash_map: hash_map[n] = 1 else: hash_map[n] += 1 min_heap = [] for num, freq in hash_map.items(): heappush(min_heap, (freq, num)) if len(min_heap) > k: heappop(min_heap) res = [] for _ in range(k): res.append(heappop(min_heap)[1]) return res

347. Top K Frequent Elements Given a non-empty array of integers, return the k most frequent elements. Input: nums = [1,1,1,2,2,3], k = 2 Output: [1,2]

Data Structure: Algorithm: Time complexity: Space complexity: class TicTacToe(object): def __init__(self, n): self.row, self.col = [0]*n, [0]*n self.diag1, self.diag2 = 0, 0 self.n = n def move(self, row, col, player): if player == 1: score = 1 elif player == 2: score = -1 self.row[row] += score self.col[col] += score if row == col: self.diag1 += score if row == self.n-col-1: self.diag2 += score if self.n in [self.row[row], self.col[col], self.diag1, self.diag2]: return 1 if -self.n in [self.row[row], self.col[col], self.diag1, self.diag2]: return 2 return 0

348. Design Tic-Tac-Toe Design a Tic-tac-toe game that is played between two players on a n x n grid. You may assume the following rules: 1. A move is guaranteed to be valid and is placed on an empty block. 2. Once a winning condition is reached, no more moves is allowed. 3. A player who succeeds in placing n of their marks in a horizontal, vertical, or diagonal row wins the game.

Data Structure: Algorithm: Time complexity: Space complexity: class SummaryRanges(object): def __init__(self): self.intervals = [] def addNum(self, val): if len(self.intervals) == 0: self.intervals.append([val, val]) return overlap = [] new_interval = [val, val] pos = 0 res = [] for interval in self.intervals: if new_interval[0] > interval[1] + 1: res.append(interval) pos += 1 elif new_interval[1] < interval[0] - 1: res.append(interval) else: new_interval[0] = min(new_interval[0], interval[0]) new_interval[1] = max(new_interval[1], interval[1]) res.insert(pos, new_interval) self.intervals = res return def getIntervals(self): return self.intervals

352. Data Stream as Disjoint Intervals Given a data stream input of non-negative integers a1, a2, ..., an, ..., summarize the numbers seen so far as a list of disjoint intervals. For example, suppose the integers from the data stream are 1, 3, 7, 2, 6, ..., then the summary will be: [1, 1] [1, 1], [3, 3] [1, 1], [3, 3], [7, 7] [1, 3], [7, 7] [1, 3], [6, 7]

Data Structure: Algorithm: Time complexity: Space complexity: class SnakeGame(object): def __init__(self, width, height, food): self. x, self. y = 0, 0 self.w, self.h = width, height self.food = food self.snake = deque() self.hashset = set() self.curr = 0 def move(self, direction): prev_x, prev_y = self.x, self.y if direction == 'U': self.x -= 1 if direction == 'D': self.x += 1 if direction == 'R': self.y += 1 if direction == 'L': self.y -= 1 if self.x < 0 or self.x >= self.h or self.y < 0 or self.y >= self.w: return -1 self.snake.appendleft([prev_x, prev_y]) self.hashset.add((prev_x, prev_y)) if self.curr < len(self.food) and self.x == self.food[self.curr][0] and self.y == self.food[self.curr][1]: self.curr += 1 else: node = self.snake.pop() self.hashset.remove(tuple(node)) if (self.x, self.y) in self.hashset: return -1 return len(self.snake)

353. Design Snake Game Design a Snake game that is played on a device with screen size = width x height. Play the game online if you are not familiar with the game. The snake is initially positioned at the top left corner (0,0) with length = 1 unit. You are given a list of food's positions in row-column order. When a snake eats the food, its length and the game's score both increase by 1. Each food appears one by one on the screen. For example, the second food will not appear until the first food was eaten by the snake. When a food does appear on the screen, it is guaranteed that it will not appear on a block occupied by the snake.

Data Structure: Algorithm: Time complexity: Space complexity: class HitCounter(object): def __init__(self): """ Initialize your data structure here. """ self.minheap = [] def hit(self, timestamp): """ Record a hit. @param timestamp - The current timestamp (in seconds granularity). :type timestamp: int :rtype: None """ while len(self.minheap) > 0 and (timestamp - self.minheap[0]) >= 300: heappop(self.minheap) heappush(self.minheap, timestamp) def getHits(self, timestamp): """ Return the number of hits in the past 5 minutes. @param timestamp - The current timestamp (in seconds granularity). :type timestamp: int :rtype: int """ while len(self.minheap) > 0 and timestamp - self.minheap[0] >= 300: heappop(self.minheap) return len(self.minheap)

362. Design Hit Counter Design a hit counter which counts the number of hits received in the past 5 minutes. Each function accepts a timestamp parameter (in seconds granularity) and you may assume that calls are being made to the system in chronological order (ie, the timestamp is monotonically increasing). You may assume that the earliest timestamp starts at 1. It is possible that several hits arrive roughly at the same time.

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def findLeaves(self, root): self.res = [] while (root): self.temp = [] root = self.dfs(root) self.res.append(self.temp) return self.res def dfs(self, root): if root is None: return None if (root.left is None) and (root.right is None): self.temp.append(root.val) return None root.left = self.dfs(root.left) root.right = self.dfs(root.right) return root

366. Find Leaves of Binary Tree Given a binary tree, collect a tree's nodes as if you were doing this: Collect and remove all leaves, repeat until the tree is empty. Input: [1,2,3,4,5] 1 / \ 2 3 / \ 4 5 Output: [[4,5,3],[2],[1]]

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def plusOne(self, head): head = self.reverse(head) carry = 1 p = head prev = ListNode(0, head) while p: val = p.val + carry carry = val / 10 p.val = val % 10 prev = p p = p.next if carry == 1: temp = ListNode(1, p) prev.next = temp return self.reverse(head) def reverse(self, head): d = None while head: temp = head.next head.next = d d = head head = temp return d

369. Plus One Linked List Given a non-negative integer represented as non-empty a singly linked list of digits, plus one to the integer. You may assume the integer do not contain any leading zero, except the number 0 itself. The digits are stored such that the most significant digit is at the head of the list. Example : Input: [1,2,3] Output: [1,2,4]

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def guessNumber(self, n): start, end = 1, n while start <= end: mid = start + (end-start)/2 if guess(mid) == 0: return mid if guess(mid) == -1: end = mid-1 else: start = mid+1 return -1

374. Guess Number Higher or Lower We are playing the Guess Game. The game is as follows: I pick a number from 1 to n. You have to guess which number I picked. Every time you guess wrong, I'll tell you whether the number is higher or lower. You call a pre-defined API guess(int num) which returns 3 possible results (-1, 1, or 0): -1 : My number is lower 1 : My number is higher 0 : Congrats! You got it!

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def findDuplicates(self, nums): hashset = set() res = [] for n in nums: if n in hashset: res.append(n) else: hashset.add(n) return res

442. Find All Duplicates in an Array Given an array of integers, 1 ≤ a[i] ≤ n (n = size of array), some elements appear twice and others appear once. Find all the elements that appear twice in this array. Could you do it without extra space and in O(n) runtime? Example: Input: [4,3,2,7,8,2,3,1] Output: [2,3]

Data Structure: Algorithm: Time complexity: Space complexity: class RandomizedSet(object): def __init__(self): """ Initialize your data structure here. """ self.hashmap = {} self.value = [] def insert(self, val): """ Inserts a value to the set. Returns true if the set did not already contain the specified element. :type val: int :rtype: bool """ if val in self.hashmap: return False self.value.append(val) self.hashmap[val] = len(self.value) - 1 return True def remove(self, val): """ Removes a value from the set. Returns true if the set contained the specified element. :type val: int :rtype: bool """ if val not in self.hashmap: return False curr_index = self.hashmap[val] last_val = self.value[-1] self.value[curr_index] = last_val self.hashmap[last_val] = curr_index self.value.pop() del self.hashmap[val] return True def getRandom(self): """ Get a random element from the set. :rtype: int """ return self.value[random.randint(0, len(self.value)-1)]

380. Insert Delete GetRandom O(1) Design a data structure that supports all following operations in average O(1) time. 1. insert(val): Inserts an item val to the set if not already present. 2. remove(val): Removes an item val from the set if present. 3. getRandom: Returns a random element from current set of elements (it's guaranteed that at least one element exists when this method is called). Each element must have the same probability of being returned.

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def canCross(self, stones): self.memo = {} return self.helper(0, 0, stones) def helper(self, curr, step, stones): if curr == (len(stones)-1): return True if (curr, step) in self.memo: return self.memo[(curr, step)] for i in range(curr+1, len(stones)): gap = stones[i] - stones[curr] if (step-1) <= gap <= (step+1) and self.helper(i, gap, stones): self.memo[(curr, step)] = True return True self.memo[(curr, step)] = False return False

403. Frog Jump A frog is crossing a river. The river is divided into x units and at each unit there may or may not exist a stone. The frog can jump on a stone, but it must not jump into the water. Given a list of stones' positions (in units) in sorted ascending order, determine if the frog is able to cross the river by landing on the last stone. Initially, the frog is on the first stone and assume the first jump must be 1 unit. If the frog's last jump was k units, then its next jump must be either k - 1, k, or k + 1 units. Note that the frog can only jump in the forward direction. Note: 1. The number of stones is ≥ 2 and is < 1,100. 2. Each stone's position will be a non-negative integer < 2^31. 3. The first stone's position is always 0. Example 1: [0,1,3,5,6,8,12,17] There are a total of 8 stones. The first stone at the 0th unit, second stone at the 1st unit, third stone at the 3rd unit, and so on... The last stone at the 17th unit.

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def splitArray(self, nums, m): n = len(nums) dp = [[0]*(m+1) for i in range(n)] cum_sum = [nums[0]] for i in range(1, n): cum_sum.append(cum_sum[-1] + nums[i]) for i in range(len(nums)): dp[i][1] = cum_sum[i] for i in range(1, len(nums)): for j in range(2, min(m, i+1)+1): temp = float('inf') for k in range(0, i): temp = min(temp, max(dp[k][j-1], cum_sum[i] - cum_sum[k])) dp[i][j] = temp return dp[len(nums)-1][m]

410. Split Array Largest Sum Given an array which consists of non-negative integers and an integer m, you can split the array into m non-empty continuous subarrays. Write an algorithm to minimize the largest sum among these m subarrays. Note:If n is the length of array, assume the following constraints are satisfied: 1 ≤ n ≤ 1000 1 ≤ m ≤ min(50, n) Input: nums = [7,2,5,10,8] m = 2 Output: 18

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def canPartition(self, nums): if sum(nums) % 2 != 0: return False w = sum(nums) / 2 n = len(nums) dp = [[False] * (w+1) for _ in range(n+1)] for i in range(n+1): dp[i][0] = True for i in range(1, n+1): for j in range(1, w+1): if j >= nums[i-1]: dp[i][j] = dp[i-1][j] or dp[i-1][j-nums[i-1]] else: dp[i][j] = dp[i-1][j] return dp[n][w]

416. Partition Equal Subset Sum Given a non-empty array containing only positive integers, find if the array can be partitioned into two subsets such that the sum of elements in both subsets is equal. Note: 1. Each of the array element will not exceed 100. 2. The array size will not exceed 200. Example 1: Input: [1, 5, 11, 5] Output: true Explanation: The array can be partitioned as [1, 5, 5] and [11].

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def characterReplacement(self, s, k): p1, res = 0, 0 hashmap = defaultdict(int) for p2, c in enumerate(s): hashmap[c] += 1 while (p2-p1+1-max(hashmap.values())) > k: hashmap[s[p1]] -= 1 p1 += 1 res = max(res, p2-p1+1) return res

424. Longest Repeating Character Replacement Given a string s that consists of only uppercase English letters, you can perform at most k operations on that string. In one operation, you can choose any character of the string and change it to any other uppercase English character. Find the length of the longest sub-string containing all repeating letters you can get after performing the above operations. Note:Both the string's length and k will not exceed 10^4. Input: s = "ABAB", k = 2 Output: 4 Explanation: Replace the two 'A's with two 'B's or vice versa.

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def eraseOverlapIntervals(self, pairs): if not pairs: return 0 n = len(pairs) pairs.sort(key=lambda x:x[0]) dp = [1] * n dp[0] = 1 for i in range(1, n): for j in range(0, i): if pairs[i][0] >= pairs[j][1]: dp[i] = max(dp[i], dp[j]+1) return n-max(dp)

435. Non-overlapping Intervals Given a collection of intervals, find the minimum number of intervals you need to remove to make the rest of the intervals non-overlapping. Example 1: Input: [[1,2],[2,3],[3,4],[1,3]] Output: 1 Explanation: [1,3] can be removed and the rest of intervals are non-overlapping.

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def pathSum(self, root, sum): self.count = 0 self.dfs(root, sum, []) return self.count def dfs(self, root, sum, path): if root is None: return path.append(root.val) path_sum, count = 0, 0 for i in range(len(path)-1, -1, -1): path_sum += path[i] if path_sum == sum: self.count+=1 self.dfs(root.left, sum, path) self.dfs(root.right, sum, path) path.pop()

437. Path Sum III You are given a binary tree in which each node contains an integer value. Find the number of paths that sum to a given value. The path does not need to start or end at the root or a leaf, but it must go downwards (traveling only from parent nodes to child nodes). The tree has no more than 1,000 nodes and the values are in the range -1,000,000 to 1,000,000. Example: root = [10,5,-3,3,2,null,11,3,-2,null,1], sum = 8 10 / \ 5 -3 / \ \ 3 2 11 / \ \ 3 -2 1 Return 3. The paths that sum to 8 are: 1. 5 -> 3 2. 5 -> 2 -> 1 3. -3 -> 11

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def isValid(self, window, need): for c in need: if window[c] < need[c]: return False return True def findAnagrams(self, s, p): left, right = 0, 0 window = {} need = {} res = [] for c in p: if c in need: need[c] += 1 else: need[c] = 1 window[c] = 0 while right < len(s): c = s[right] if c in window: window[c] += 1 while self.isValid(window, need): if (right - left + 1) == len(p): res.append(left) c = s[left] if c in window: window[c] = max(0, window[c] - 1) left += 1 right += 1 return res

438. Find All Anagrams in a String Given a string s and a non-empty string p, find all the start indices of p's anagrams in s. Strings consists of lowercase English letters only and the length of both strings s and p will not be larger than 20,100. The order of output does not matter. Input: s: "cbaebabacd" p: "abc" Output: [0, 6] Explanation: The substring with start index = 0 is "cba", which is an anagram of "abc". The substring with start index = 6 is "bac", which is an anagram of "abc".

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def deleteNode(self, root, key): if root is None: return None if root.val == key: if root.left == None: return root.right if root.right == None: return root.left minNode = self.getMin(root.right) root.val = minNode.val root.right = self.deleteNode(root.right, minNode.val) elif key < root.val: root.left = self.deleteNode(root.left, key) elif key > root.val: root.right = self.deleteNode(root.right, key) return root def getMin(self, node): while node.left is not None: node = node.left return node

450. Delete Node in a BST Given a root node reference of a BST and a key, delete the node with the given key in the BST. Return the root node reference (possibly updated) of the BST. Basically, the deletion can be divided into two stages: 1. Search for a node to remove. 2. If the node is found, delete the node. Note: Time complexity should be O(height of tree).

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def frequencySort(self, s): hash_table = {} for c in s: if c in hash_table: hash_table[c] += 1 else: hash_table[c] = 1 max_heap = [] for c, freq in hash_table.items(): heappush(max_heap, (-freq, c)) res = '' while max_heap: freq, c = heappop(max_heap) for _ in range(-freq): res+=c return res

451. Sort Characters By Frequency Given a string, sort it in decreasing order based on the frequency of characters. Example 1: Input: "tree" Output: "eert" Explanation: 'e' appears twice while 'r' and 't' both appear once. So 'e' must appear before both 'r' and 't'. Therefore "eetr" is also a valid answer.

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def findMinArrowShots(self, points): if len(points) == 0: return 0 points.sort(key = lambda x : x[1]) res = 1 end = points[0][1] for p in points[1:]: if p[0] > end: res += 1 end = p[1] return res

452. Minimum Number of Arrows to Burst Balloons There are a number of spherical balloons spread in two-dimensional space. For each balloon, provided input is the start and end coordinates of the horizontal diameter. Since it's horizontal, y-coordinates don't matter and hence the x-coordinates of start and end of the diameter suffice. Start is always smaller than end. There will be at most 10^4 balloons. An arrow can be shot up exactly vertically from different points along the x-axis. A balloon with x_start and x_end bursts by an arrow shot at x if x_start ≤ x ≤ x_end. There is no limit to the number of arrows that can be shot. An arrow once shot keeps travelling up infinitely. The problem is to find the minimum number of arrows that must be shot to burst all balloons. Input: [[10,16], [2,8], [1,6], [7,12]] Output: 2 Explanation: One way is to shoot one arrow for example at x = 6 (bursting the balloons [2,8] and [1,6]) and another arrow at x = 11 (bursting the other two balloons).

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def fib(self, N): if N < 2: return N prev, curr = 0, 1 for i in range(2, N+1): next = prev + curr prev = curr curr = next return curr

509. Fibonacci Number The Fibonacci numbers, commonly denoted F(n) form a sequence, called the Fibonacci sequence, such that each number is the sum of the two preceding ones, starting from 0 and 1. That is, F(0) = 0, F(1) = 1 F(N) = F(N - 1) + F(N - 2), for N > 1. Given N, calculate F(N).

Data Structure: Algorithm: Time complexity: Space complexity: class KeyNode(object): def __init__(self, key, value, freq = 1): self.key = key self.value = value self.freq = freq self.prev = self.next = None class FreqNode(object): def __init__(self, freq, prev, next): self.freq = freq self.prev = prev self.next = next self.first = self.last = None class LFUCache(object): def __init__(self, capacity): self.capacity = capacity self.keyDict = dict() self.freqDict = dict() self.head = None def get(self, key): if key in self.keyDict: keyNode = self.keyDict[key] value = keyNode.value self.increase(key, value) return value return -1 def put(self, key, value): if self.capacity == 0: return if key in self.keyDict: self.increase(key, value) return if len(self.keyDict) == self.capacity: last_node = self.head.last self.unlinkKey(last_node, self.freqDict[last_node.freq]) del self.keyDict[last_node.key] keyNode = self.keyDict[key] = KeyNode(key, value) freqNode = self.freqDict.get(1) if freqNode is None: freqNode = self.freqDict[1] = FreqNode(1, None, self.head) if self.head: self.head.prev = freqNode self.head = freqNode self.linkKey(keyNode, freqNode) def increase(self, key, value): keyNode = self.keyDict[key] keyNode.value = value freqNode = self.freqDict[keyNode.freq] nextFreqNode = freqNode.next keyNode.freq += 1 if nextFreqNode is None or nextFreqNode.freq > keyNode.freq: nextFreqNode = FreqNode(keyNode.freq, freqNode, freqNode.next) self.freqDict[keyNode.freq] = nextFreqNode if freqNode.next: freqNode.next.prev = nextFreqNode freqNode.next = nextFreqNode self.unlinkKey(keyNode, freqNode) self.linkKey(keyNode, nextFreqNode) def unlinkKey(self, keyNode, freqNode): next, prev = keyNode.next, keyNode.prev if prev: prev.next = next if next: next.prev = prev if freqNode.first == keyNode: freqNode.first = next if freqNode.last == keyNode: freqNode.last = prev if freqNode.first is None: prev, next = freqNode.prev, freqNode.next if prev: prev.next = next if next: next.prev = prev if self.head == freqNode: self.head = next del self.freqDict[freqNode.freq] def linkKey(self, keyNode, freqNode): firstKeyNode = freqNode.first keyNode.prev = None keyNode.next = firstKeyNode if firstKeyNode: firstKeyNode.prev = keyNode freqNode.first = keyNode if freqNode.last is None: freqNode.last = keyNode

460. LFU Cache Design and implement a data structure for Least Frequently Used (LFU) cache. It should support the following operations: get and put. get(key) - Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1. put(key, value) - Set or insert the value if the key is not already present. When the cache reaches its capacity, it should invalidate the least frequently used item before inserting a new item. For the purpose of this problem, when there is a tie (i.e., two or more keys that have the same frequency), the least recently used key would be evicted. Note that the number of times an item is used is the number of calls to the get and put functions for that item since it was inserted. This number is set to zero when the item is removed. Follow up:Could you do both operations in O(1) time complexity?

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def islandPerimeter(self, grid): m = len(grid) n = len(grid[0]) direction = [[1, 0], [0, 1], [-1, 0], [0, -1]] res = 0 for i in range(0, m): for j in range(0, n): if grid[i][j] == 0: continue temp = 4 for d in direction: x, y = i + d[0], j + d[1] if x < 0 or x >= m or y < 0 or y >= n: continue if grid[x][y] == 1: temp -= 1 res += temp return res

463. Island Perimeter You are given a map in form of a two-dimensional integer grid where 1 represents land and 0 represents water. Grid cells are connected horizontally/vertically (not diagonally). The grid is completely surrounded by water, and there is exactly one island (i.e., one or more connected land cells). The island doesn't have "lakes" (water inside that isn't connected to the water around the island). One cell is a square with side length 1. The grid is rectangular, width and height don't exceed 100. Determine the perimeter of the island. Input: [[0,1,0,0], [1,1,1,0], [0,1,0,0], [1,1,0,0]] Output: 16

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def minTransfers(self, transactions): hashmap = defaultdict(int) for x, y, z in transactions: hashmap[x] += z hashmap[y] -= z balance = [] for i in hashmap: if hashmap[i] != 0: balance.append(hashmap[i]) return self.backtrack(0, balance) def backtrack(self, i, balance): while i < len(balance) and balance[i] == 0: i += 1 if i == len(balance): return 0 res = float('inf') for j in range(i+1, len(balance)): if balance[i] * balance[j] < 0: balance[j] += balance[i] res = min(res, 1 + self.backtrack(i+1, balance)) balance[j] -= balance[i] if balance[i] + balance[j] == 0: break return res

465. Optimal Account Balancing A group of friends went on holiday and sometimes lent each other money. For example, Alice paid for Bill's lunch for $10. Then later Chris gave Alice $5 for a taxi ride. We can model each transaction as a tuple (x, y, z) which means person x gave person y $z. Assuming Alice, Bill, and Chris are person 0, 1, and 2 respectively (0, 1, 2 are the person's ID), the transactions can be represented as [[0, 1, 10], [2, 0, 5]]. Given a list of transactions between a group of people, return the minimum number of transactions required to settle the debt. Note: 1. A transaction will be given as a tuple (x, y, z). Note that x ≠ y and z > 0. 2. Person's IDs may not be linear, e.g. we could have the persons 0, 1, 2 or we could also have the persons 0, 2, 6. Input: [[0,1,10], [2,0,5]] Output: 2 Explanation: Person #0 gave person #1 $10. Person #2 gave person #0 $5. Two transactions are needed. One way to settle the debt is person #1 pays person #0 and #2 $5 each.

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def findAllConcatenatedWordsInADict(self, words): self.words = set(words) res = [] for w in words: self.words.remove(w) if self.helper(w): res.append(w) self.words.add(w) return res def helper(self, w): if w in self.words: return True res = False for i in range(1, len(w)): if w[:i] in self.words and self.helper(w[i:]): return True return False

472. Concatenated Words Given a list of words (without duplicates), please write a program that returns all concatenated words in the given list of words. A concatenated word is defined as a string that is comprised entirely of at least two shorter words in the given array. Input: ["cat","cats","catsdogcats","dog","dogcatsdog","hippopotamuses","rat","ratcatdogcat"] Output: ["catsdogcats","dogcatsdog","ratcatdogcat"] Explanation: "catsdogcats" can be concatenated by "cats", "dog" and "cats"; "dogcatsdog" can be concatenated by "dog", "cats" and "dog"; "ratcatdogcat" can be concatenated by "rat", "cat", "dog" and "cat".

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def __init__(self): self.maxheap = [] self.minheap = [] def balanceHeap(self): while len(self.maxheap) > len(self.minheap) + 1: heappush(self.minheap, -heappop(self.maxheap)) while len(self.maxheap) < len(self.minheap): heappush(self.maxheap, -heappop(self.minheap)) def removeHeap(self, heap, index): ind = heap.index(index) heap[ind] = heap[-1] del heap[-1] if ind < len(heap): heapq._siftup(heap, ind) heapq._siftdown(heap, 0, ind) def medianSlidingWindow(self, nums, k): res = [] p1 = 0 for p2 in range(len(nums)): if not self.maxheap or -nums[p2] > self.maxheap[0]: heappush(self.maxheap, -nums[p2]) else: heappush(self.minheap, nums[p2]) self.balanceHeap() if (p2 - p1) == (k - 1): if len(self.maxheap) == len(self.minheap): res.append(-self.maxheap[0]/2.0 + self.minheap[0]/2.0) else: res.append(-self.maxheap[0]) if nums[p1] <= -self.maxheap[0]: self.removeHeap(self.maxheap, -nums[p1]) else: self.removeHeap(self.minheap, nums[p1]) self.balanceHeap() p1 += 1 return res

480. Sliding Window Median Median is the middle value in an ordered integer list. If the size of the list is even, there is no middle value. So the median is the mean of the two middle value. Examples: [2,3,4] , the median is 3 [2,3], the median is (2 + 3) / 2 = 2.5 Given an array nums, there is a sliding window of size k which is moving from the very left of the array to the very right. You can only see the k numbers in the window. Each time the sliding window moves right by one position. Your job is to output the median array for each window in the original array. For example, Given nums = [1,3,-1,-3,5,3,6,7], and k = 3. Window position Median --------------- ----- [1 3 -1] -3 5 3 6 7 1 1 [3 -1 -3] 5 3 6 7 -1 1 3 [-1 -3 5] 3 6 7 -1 1 3 -1 [-3 5 3] 6 7 3 1 3 -1 -3 [5 3 6] 7 5 1 3 -1 -3 5 [3 6 7] 6 Therefore, return the median sliding window as [1,-1,-1,3,5,6].

Data Structure: Algorithm: Monotonic Increasing Stack Time complexity: Space complexity: class Solution(object): def nextGreaterElement(self, nums1, nums2): stack = [] res = [-1] * len(nums2) ans = [-1] * len(nums1) for i in range(len(nums2)-1, -1, -1): while len(stack) > 0 and nums2[i] > stack[-1]: stack.pop() if len(stack) > 0: res[i] = stack[-1] stack.append(nums2[i]) for i, n in enumerate(nums1): j = nums2.index(n) ans[i] = res[j] return ans

496. Next Greater Element I You are given two arrays (without duplicates) nums1 and nums2 where nums1's elements are subset of nums2. Find all the next greater numbers for nums1's elements in the corresponding places of nums2. The Next Greater Number of a number x in nums1 is the first greater number to its right in nums2. If it does not exist, output -1 for this number.

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def nextGreaterElements(self, nums): n = len(nums) stack = [] res = [-1] * n for i in range(2*n-1, -1, -1): while len(stack) > 0 and nums[i%n] >= stack[-1]: stack.pop() if len(stack) > 0: res[i%n] = stack[-1] stack.append(nums[i%n]) return res

503. Next Greater Element II Given a circular array (the next element of the last element is the first element of the array), print the Next Greater Number for every element. The Next Greater Number of a number x is the first greater number to its traversing-order next in the array, which means you could search circularly to find its next greater number. If it doesn't exist, output -1 for this number.

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def longestPalindromeSubseq(self, s): n = len(s) if n < 2: return n if n == 2: return 2 if s[0] == s[1] else 1 dp = [[0]*n for _ in range(n)] for i in range(n-1): dp[i][i] = 1 if s[i] == s[i+1]: dp[i][i+1] = 2 else: dp[i][i+1] = 1 dp[n-1][n-1] = 1 for i in range(n-3, -1, -1): for j in range(i+2, n): if s[i] == s[j]: dp[i][j] = 2 + dp[i+1][j-1] else: dp[i][j] = max(dp[i+1][j], dp[i][j-1]) return dp[0][n-1]

516. Longest Palindromic Subsequence Given a string s, find the longest palindromic subsequence's length in s. You may assume that the maximum length of s is 1000. Example 1: Input: "bbbab" Output: 4

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def change(self, amount, coins): n = len(coins) dp = [[0] * (amount+1) for _ in range(n+1)] for i in range(n+1): dp[i][0] = 1 for i in range(1, n+1): for j in range(1, amount+1): if j >= coins[i-1]: dp[i][j] = dp[i-1][j] + dp[i][j-coins[i-1]] else: dp[i][j] = dp[i-1][j] return dp[n][amount]

518. Coin Change 2 You are given coins of different denominations and a total amount of money. Write a function to compute the number of combinations that make up that amount. You may assume that you have infinite number of each kind of coin.

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def __init__(self): self.max_path = 0 def diameterOfBinaryTree(self, root): self.dfs(root) return self.max_path def dfs(self, root): if root is None: return -1 left_height = self.dfs(root.left) right_height = self.dfs(root.right) self.max_path = max(self.max_path, left_height + right_height + 2) return max(left_height, right_height) + 1

543. Diameter of Binary Tree Given a binary tree, you need to compute the length of the diameter of the tree. The diameter of a binary tree is the length of the longest path between any two nodes in a tree. This path may or may not pass through the root.

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def isValid(self, window, need): for key in need: if window[key] < need[key]: return False return True def checkInclusion(self, s1, s2): left, right = 0, 0 need = {} window = {} for c in s1: window[c] = 0 if c in need: need[c] += 1 else: need[c] = 1 while right < len(s2): c = s2[right] if c in window: window[c] += 1 while self.isValid(window, need): if (right - left + 1) == len(s1): return True c = s2[left] if c in window: window[c] = max(0, window[c] - 1) left += 1 right += 1 return False

567. Permutation in String 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.

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def isEqual(self, s, t): if not t and not s: return True if not t or not s or s.val != t.val: return False return self.isEqual(s.left, t.left) and self.isEqual(s.right, t.right) def isSubtree(self, s, t): if not t and not s: return True if not t or not s: return False if self.isEqual(s, t): return True return self.isSubtree(s.left, t) or self.isSubtree(s.right, t)

572. Subtree of Another Tree Given two non-empty binary trees s and t, check whether tree t has exactly the same structure and node values with a subtree of s. A subtree of s is a tree consists of a node in s and all of this node's descendants. The tree s could also be considered as a subtree of itself.

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def findLongestChain(self, pairs): pairs.sort() n = len(pairs) dp = [1] * n for i in range(1, n): for k in range(i): if pairs[i][0] > pairs[k][1]: dp[i] = max(dp[i], dp[k] + 1) return dp[n-1]

646. Maximum Length of Pair Chain You are given n pairs of numbers. In every pair, the first number is always smaller than the second number. Now, we define a pair (c, d) can follow another pair (a, b) if and only if b < c. Chain of pairs can be formed in this fashion. Given a set of pairs, find the length longest chain which can be formed. You needn't use up all the given pairs. You can select pairs in any order. Input: [[1,2], [2,3], [3,4]] Output: 2 Explanation: The longest chain is [1,2] -> [3,4]

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def maxA(self, N): dp = [0] * (N+1) for i in range(1, N+1): dp[i] = 1 + dp[i-1] for k in range(i-3, -1, -1): dp[i] = max(dp[i], (i-k-1)*dp[k]) return dp[N]

651. 4 Keys Keyboard Imagine you have a special keyboard with the following keys: Key 1: (A): Print one 'A' on screen. Key 2: (Ctrl-A): Select the whole screen. Key 3: (Ctrl-C): Copy selection to buffer. Key 4: (Ctrl-V): Print buffer on screen appending it after what has already been printed. Now, you can only press the keyboard for N times (with the above four keys), find out the maximum numbers of 'A' you can print on screen.

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def findClosestElements(self, arr, k, x): start = 0 end = len(arr) - 1 while start <= end: mid = start + (end - start) / 2 if x <= arr[mid]: end = mid-1 else: start = mid+1 p1 = max(0, start - k - 1) p2 = min(len(arr) - 1, start + k - 1) while p2 - p1 > k - 1: if p1 < 0 or ((x - arr[p1]) <= (arr[p2] - x)): p2 -= 1 elif p2 > len(arr) - 1 or ((x - arr[p1]) > (arr[p2]) - x): p1 += 1 return arr[p1:p2+1]

658. Find K Closest Elements Given a sorted array arr, two integers k and x, find the k closest elements to x in the array. The result should also be sorted in ascending order. If there is a tie, the smaller elements are always preferred. Input: arr = [1,2,3,4,5], k = 4, x = 3 Output: [1,2,3,4]

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def topKFrequent(self, words, k): hashmap = defaultdict(int) for w in words: hashmap[w] += 1 heap = [] heapq.heapify(heap) for key in hashmap: heappush(heap, (-hashmap[key], key)) res = [] for _ in range(k): res.append(heap[0][1]) heappop(heap) return res

692. Top K Frequent Words Given a non-empty list of words, return the k most frequent elements. Your answer should be sorted by frequency from highest to lowest. If two words have the same frequency, then the word with the lower alphabetical order comes first. Example 1: Input: ["i", "love", "leetcode", "i", "love", "coding"], k = 2 Output: ["i", "love"] Explanation: "i" and "love" are the two most frequent words. Note that "i" comes before "love" due to a lower alphabetical order.

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def numDistinctIslands(self, grid): shape = set() self.m, self.n = len(grid), len(grid[0]) self.grid = grid for i in range(self.m): for j in range(self.n): if grid[i][j] == 1: self.rel_pos = [] self.dfs(i, j, i, j) shape.add(tuple(self.rel_pos)) return len(shape) def dfs(self, x, y, start_x, start_y): if x < 0 or y < 0 or x >= self.m or y >= self.n or self.grid[x][y] == 0: return self.grid[x][y] = 0 self.rel_pos.append((x-start_x, y-start_y)) direction = [[1, 0], [0, 1], [-1, 0], [0, -1]] for d in direction: self.dfs(x+d[0], y+d[1], start_x, start_y)

694. Number of Distinct Islands Given a non-empty 2D array grid of 0's and 1's, an island is a group of 1's (representing land) connected 4-directionally (horizontal or vertical.) You may assume all four edges of the grid are surrounded by water. Count the number of distinct islands. An island is considered to be the same as another if and only if one island can be translated (and not rotated or reflected) to equal the other.

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def maxAreaOfIsland(self, grid): res = 0 self.grid = grid for i in range(len(self.grid)): for j in range(len(self.grid[0])): if self.grid[i][j] == 1: res = max(res, self.dfs(i, j)) return res def dfs(self, i, j): if i < 0 or j < 0 or i >= len(self.grid) or j >= len(self.grid[0]) or self.grid[i][j] == 0: return 0 self.grid[i][j] = 0 return 1 + self.dfs(i, j-1) + self.dfs(i, j+1) + self.dfs(i-1, j) + self.dfs(i+1, j)

695. Max Area of Island Given a non-empty 2D array grid of 0's and 1's, an island is a group of 1's (representing land) connected 4-directionally (horizontal or vertical.) You may assume all four edges of the grid are surrounded by water. Find the maximum area of an island in the given 2D array. (If there is no island, the maximum area is 0.)

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def searchBST(self, root, val): if root is None: return None if root.val == val: return root if root.val < val: return self.searchBST(root.right, val) if root.val > val: return self.searchBST(root.left, val)

700. Search in a Binary Search Tree Given the root node of a binary search tree (BST) and a value. You need to find the node in the BST that the node's value equals the given value. Return the subtree rooted with that node. If such node doesn't exist, you should return NULL. For example, Given the tree: 4 / \ 2 7 / \ 1 3 And the value to search: 2 You should return this subtree: 2 / \ 1 3

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def insertIntoBST(self, root, val): if root is None: return TreeNode(val) if root.val < val: root.right = self.insertIntoBST(root.right, val) else: root.left = self.insertIntoBST(root.left, val) return root

701. Insert into a Binary Search Tree Given the root node of a binary search tree (BST) and a value to be inserted into the tree, insert the value into the BST. Return the root node of the BST after the insertion. It is guaranteed that the new value does not exist in the original BST. Note that there may exist multiple valid ways for the insertion, as long as the tree remains a BST after insertion. You can return any of them. Constraints: The number of nodes in the given tree will be between 0 and 10^4. Each node will have a unique integer value from 0 to -10^8, inclusive. -10^8 <= val <= 10^8 It's guaranteed that val does not exist in the original BST.

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def search(self, reader, target): if reader.get(0) > target: return -1 p1 = 0 p2 = 1 while reader.get(p2) < target: p1 = p2 p2 *= 2 start = p1 end = p2 while start + 1 < end: mid = start + (end-start) / 2 if reader.get(mid) == target: return mid elif reader.get(mid) < target: start = mid else: end = mid if reader.get(start) == target: return start if reader.get(end) == target: return end return -1

702. Search in a Sorted Array of Unknown Size Given an integer array sorted in ascending order, write a function to search target in nums. If target exists, then return its index, otherwise return -1. However, the array size is unknown to you. You may only access the array using an ArrayReader interface, where ArrayReader.get(k) returns the element of the array at index k (0-indexed). You may assume all integers in the array are less than 10000, and if you access the array out of bounds, ArrayReader.get will return 2147483647.

Data Structure: Algorithm: Time complexity: Space complexity: class KthLargest(object): def __init__(self, k, nums): self.min_heap = [] for i in range(k): if i > (len(nums) - 1): heappush(self.min_heap, -float("inf")) else: heappush(self.min_heap, nums[i]) for i in range(k, len(nums)): if nums[i] > self.min_heap[0]: heappush(self.min_heap, nums[i]) heappop(self.min_heap) def add(self, val): if val > self.min_heap[0]: heappush(self.min_heap, val) heappop(self.min_heap) return self.min_heap[0]

703. Kth Largest Element in a Stream Design a class to find the kth largest element in a stream. Note that it is the kth largest element in the sorted order, not the kth distinct element. Your KthLargest class will have a constructor which accepts an integer k and an integer array nums, which contains initial elements from the stream. For each call to the method KthLargest.add, return the element representing the kth largest element in the stream.

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def numSubarrayProductLessThanK(self, nums, k): if not nums: return 0 p1 = 0 res = 0 product = 1 for p2 in range(len(nums)): product *= nums[p2] while product >= k and p1 <= p2: product /= nums[p1] p1 += 1 res += p2-p1+1 return res

713. Subarray Product Less Than K Your are given an array of positive integers nums. Count and print the number of (contiguous) subarrays where the product of all the elements in the subarray is less than k. Input: nums = [10, 5, 2, 6], k = 100 Output: 8 Explanation: The 8 subarrays that have product less than 100 are: [10], [5], [2], [6], [10, 5], [5, 2], [2, 6], [5, 2, 6]. Note that [10, 5, 2] is not included as the product of 100 is not strictly less than k.

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def maxProfit(self, prices, fee): n = len(prices) dp = [[0] * 2 for _ in range(n+1)] dp[0][0] = 0 dp[0][1] = -float('inf') for i in range(1, n+1): dp[i][0] = max(dp[i-1][0], dp[i-1][1] + prices[i-1] - fee) dp[i][1] = max(dp[i-1][1], dp[i-1][0] - prices[i-1]) return dp[n][0]

714. Best Time to Buy and Sell Stock with Transaction Fee Your are given an array of integers prices, for which the i-th element is the price of a given stock on day i; and a non-negative integer fee representing a transaction fee. You may complete as many transactions as you like, but you need to pay the transaction fee for each transaction. You may not buy more than 1 share of a stock at a time (ie. you must sell the stock share before you buy again.) Return the maximum profit you can make. Note: 0 < prices.length <= 50000. 0 < prices[i] < 50000. 0 <= fee < 50000.

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def floodFill(self, image, sr, sc, newColor): oldColor = image[sr][sc] if newColor == oldColor: return image m, n = len(image), len(image[0]) direction = [[1, 0], [0, 1], [-1, 0], [0, -1]] q = deque() q.append([sr, sc]) while q: i, j = q.pop() image[i][j] = newColor for d in direction: i_, j_ = i+d[0], j+d[1] if 0<=i_<m and 0<=j_<n and image[i_][j_] == oldColor: q.append([i_, j_]) return image

733. Flood Fill An image is represented by a 2-D array of integers, each integer representing the pixel value of the image (from 0 to 65535). Given a coordinate (sr, sc) representing the starting pixel (row and column) of the flood fill, and a pixel value newColor, "flood fill" the image. To perform a "flood fill", consider the starting pixel, plus any pixels connected 4-directionally to the starting pixel of the same color as the starting pixel, plus any pixels connected 4-directionally to those pixels (also with the same color as the starting pixel), and so on. Replace the color of all of the aforementioned pixels with the newColor. At the end, return the modified image.

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def dailyTemperatures(self, T): n = len(T) res = [0] * n stack = [] for i in range(n-1, -1, -1): while len(stack) > 0 and T[i] >= T[stack[-1]]: stack.pop() if len(stack) > 0: res[i] = stack[-1] - i stack.append(i) return res

739. Daily Temperatures Given a list of daily temperatures T, return a list such that, for each day in the input, tells you how many days you would have to wait until a warmer temperature. If there is no future day for which this is possible, put 0 instead. For example, given the list of temperatures T = [73, 74, 75, 71, 69, 72, 76, 73], your output should be [1, 1, 4, 2, 1, 1, 0, 0].

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def nextGreatestLetter(self, letters, target): if target < letters[0] or target >= letters[-1]: return letters[0] start = 0 end = len(letters) - 1 while start <= end: mid = start + (end - start) / 2 if letters[mid] <= target: start = mid+1 else: right_bound = mid end = mid - 1 return letters[right_bound]

744. Find Smallest Letter Greater Than Target Given a list of sorted characters letters containing only lowercase letters, and given a target letter target, find the smallest element in the list that is larger than the given target. Letters also wrap around. For example, if the target is target = 'z' and letters = ['a', 'b'], the answer is 'a'.

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def openLock(self, deadends, target): start = "0000" if target in deadends or start in deadends: return -1 res = 0 visited = set() q1 = set() q2 = set() q1.add(start) q2.add(target) while q1 and q2: temp = set() for curr in q1: if curr in deadends: continue if curr in q2: return res visited.add(curr) for bit in range(0, 4): for dir in (-1, 1): new_bit = (int(curr[bit])+dir) % 10 new = curr[0:bit] + str(new_bit) + curr[bit+1:] if new not in visited: temp.add(new) res += 1 q1 = q2 q2 = temp return -1

752. Open the Lock You have a lock in front of you with 4 circular wheels. Each wheel has 10 slots: '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'. The wheels can rotate freely and wrap around: for example we can turn '9' to be '0', or '0' to be '9'. Each move consists of turning one wheel one slot. The lock initially starts at '0000', a string representing the state of the 4 wheels. You are given a list of deadends dead ends, meaning if the lock displays any of these codes, the wheels of the lock will stop turning and you will be unable to open it. Given a target representing the value of the wheels that will unlock the lock, return the minimum total number of turns required to open the lock, or -1 if it is impossible.

Data Structure: Algorithm: Greedy Time complexity: Space complexity: class Solution(object): def partitionLabels(self, S): res = [] self.hashmap = defaultdict(int) for i, c in enumerate(S): self.hashmap[c] = max(self.hashmap[c], i) start = 0 end = 0 while start < len(S): i = start end = self.hashmap[S[i]] while i <= end: if self.hashmap[S[i]] > end: end = self.hashmap[S[i]] i += 1 res.append(end-start+1) start = end+1 return res

763. Partition Labels A string S of lowercase English letters is given. We want to partition this string into as many parts as possible so that each letter appears in at most one part, and return a list of integers representing the size of these parts. Input: S = "ababcbacadefegdehijhklij" Output: [9,7,8] Explanation: The partition is "ababcbaca", "defegde", "hijhklij". This is a partition so that each letter appears in at most one part. A partition like "ababcbacadefegde", "hijhklij" is incorrect, because it splits S into less parts.

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def reorganizeString(self, S): count = collections.Counter(S) maxheap = [(-v, c) for c, v in count.items()] heapq.heapify(maxheap) prev_c, prev_f = None, 0 res = [] while maxheap: freq, c = heappop(maxheap) if prev_c and -prev_f > 0: heappush(maxheap, (prev_f, prev_c)) res.append(c) prev_c = c prev_f = freq+1 return ''.join(res) if len(res) == len(S) else ""

767. Reorganize String Given a string S, check if the letters can be rearranged so that two characters that are adjacent to each other are not the same. If possible, output any possible result. If not possible, return the empty string. Example 1: Input: S = "aab" Output: "aba"

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def numBusesToDestination(self, routes, S, T): if S == T: return 0 hashmap = defaultdict(list) hashset = set() for i, stops in enumerate(routes): for s in stops: hashmap[s].append(i) q = deque() q.append(S) res = 0 while q: res += 1 length = len(q) for _ in range(length): node = q.popleft() for bus in hashmap[node]: if bus in hashset: continue hashset.add(bus) for stop in routes[bus]: if stop == T: return res q.append(stop) return -1

815. Bus Routes We have a list of bus routes. Each routes[i] is a bus route that the i-th bus repeats forever. For example if routes[0] = [1, 5, 7], this means that the first bus (0-th indexed) travels in the sequence 1->5->7->1->5->7->1->... forever. We start at bus stop S (initially not on a bus), and we want to go to bus stop T. Travelling by buses only, what is the least number of buses we must take to reach our destination? Return -1 if it is not possible. Example: Input: routes = [[1, 2, 7], [3, 6, 7]] S = 1 T = 6 Output: 2 Explanation: The best strategy is take the first bus to the bus stop 7, then take the second bus to the bus stop 6.

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def mostCommonWord(self, paragraph, banned): words = [] temp = '' for c in paragraph: if lower(c) in 'abcdefghijklmnopqrstuvwxyz': temp += lower(c) else: if temp != '': words.append(temp) temp = '' if temp != '': words.append(temp) count = collections.Counter(words) res, best = '', 0 for w, f in count.items(): if f > best and w not in banned: res, best = w, f return res

819. Most Common Word Given a paragraph and a list of banned words, return the most frequent word that is not in the list of banned words. It is guaranteed there is at least one word that isn't banned, and that the answer is unique. Words in the list of banned words are given in lowercase, and free of punctuation. Words in the paragraph are not case sensitive. The answer is in lowercase.

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def largestIsland(self, grid): m = len(grid) self.grid = grid self.directions = [[0, 1], [1, 0], [0, -1], [-1, 0]] index = 2 area = {} for i in range(m): for j in range(m): if self.grid[i][j] == 1: area[index] = self.dfs(i, j, index) index += 1 if not area: return 1 res = max(0, max(area.values())) for i in range(m): for j in range(m): if self.grid[i][j] == 0: index = set() for d in self.directions: if 0<=i+d[0]<m and 0<=j+d[1]<m: index.add(self.grid[i+d[0]][j+d[1]]) temp = 1 for ind in index: if ind > 1: temp += area[ind] res = max(res, temp) return res def dfs(self, i, j, index): m = len(self.grid) self.grid[i][j] = index res = 1 for d in self.directions: if 0<=(i+d[0])<m and 0<=(j+d[1])<m and self.grid[i+d[0]][j+d[1]] == 1: res += self.dfs(i+d[0], j+d[1], index) return res

827. Making A Large Island In a 2D grid of 0s and 1s, we change at most one 0 to a 1. After, what is the size of the largest island? (An island is a 4-directionally connected group of 1s). Example 1: Input: [[1, 0], [0, 1]] Output: 3 Explanation: Change one 0 to 1 and connect two 1s, then we get an island with area = 3. Example 2: Input: [[1, 1], [1, 0]] Output: 4 Explanation: Change the 0 to 1 and make the island bigger, only one island with area = 4. Example 3: Input: [[1, 1], [1, 1]] Output: 4 Explanation: Can't change any 0 to 1, only one island with area = 4.

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def kSimilarity(self, A, B): q = deque() q.append(A) res = {A: 0} while q: C = q.popleft() if (C == B): return res[C] for i in range(len(C)): if (C[i] != B[i]): break for j in range(i+1, len(C)): if C[j] == B[i]: D = list(C) D[i], D[j] = D[j], D[i] D = ''.join(D) if D not in res: q.append(D) res[D] = res[C] + 1 return 0

854. K-Similar Strings Strings A and B are K-similar (for some non-negative integer K) if we can swap the positions of two letters in A exactly K times so that the resulting string equals B. Given two anagrams A and B, return the smallest K for which A and B are K-similar.

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def distanceK(self, root, target, K): self.graph = defaultdict(list) self.dfs(root) q = collections.deque() q.append(target.val) dist = 0 visited = set() while q: size = len(q) if dist == K: break for _ in range(size): node = q.popleft() visited.add(node) for child in self.graph[node]: if child not in visited: q.append(child) dist += 1 return list(q) def dfs(self, root): if root is None: return if root.left: self.graph[root.val].append(root.left.val) self.graph[root.left.val].append(root.val) self.dfs(root.left) if root.right: self.graph[root.val].append(root.right.val) self.graph[root.right.val].append(root.val) self.dfs(root.right)

863. All Nodes Distance K in Binary Tree We are given a binary tree (with root node root), a target node, and an integer value K. Return a list of the values of all nodes that have a distance K from the target node. The answer can be returned in any order.

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def middleNode(self, head): slow = head fast = head while fast is not None and fast.next is not None: slow = slow.next fast = fast.next.next return slow

876. Middle of the Linked List Given a non-empty, singly linked list with head node head, return a middle node of linked list. If there are two middle nodes, return the second middle node.

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def rangeSumBST(self, root, L, R): if not root: return 0 stack = [root] res = 0 while stack: node = stack.pop() if not node: continue if L <= node.val <= R: res += node.val if node.val < R: stack.append(node.right) if node.val > L: stack.append(node.left) return res

938. Range Sum of BST Given the root node of a binary search tree, return the sum of values of all nodes with value between L and R (inclusive). The binary search tree is guaranteed to have unique values. Example 1: Input: root = [10,5,15,3,7,null,18], L = 7, R = 15 Output: 32

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def stoneGame(self, piles): n = len(piles) dp = [[[0]*2 for _ in range(n)] for _ in range(n)] for i in range(n): dp[i][i][0] = piles[i] dp[i][i][1] = 0 for i in range(n-2, -1, -1): for j in range(i+1, n): left = piles[i] + dp[i+1][j][1] right = piles[j] + dp[i][j-1][1] if left > right: dp[i][j][0] = left dp[i][j][1] = dp[i+1][j][0] else: dp[i][j][0] = right dp[i][j][1] = dp[i][j-1][0] return dp[0][n-1][0] > dp[0][n-1][1]

877. Stone Game Alex and Lee play a game with piles of stones. There are an even number of piles arranged in a row, and each pile has a positive integer number of stones piles[i]. The objective of the game is to end with the most stones. The total number of stones is odd, so there are no ties. Alex and Lee take turns, with Alex starting first. Each turn, a player takes the entire pile of stones from either the beginning or the end of the row. This continues until there are no more piles left, at which point the person with the most stones wins. Assuming Alex and Lee play optimally, return True if and only if Alex wins the game. Example 1: Input: [5,3,4,5] Output: true Explanation: Alex starts first, and can only take the first 5 or the last 5. Say he takes the first 5, so that the row becomes [3, 4, 5]. If Lee takes 3, then the board is [4, 5], and Alex takes 5 to win with 10 points. If Lee takes the last 5, then the board is [3, 4], and Alex takes 4 to win with 9 points. This demonstrated that taking the first 5 was a winning move for Alex, so we return true.

Data Structure: Let dp(K, N) be the maximum number of moves needed to solve the problem in state (K, N) Algorithm: dp(K,N)=1≤X≤Nmin​(max(dp(K−1,X−1),dp(K,N−X))) Time complexity: Space complexity: class Solution(object): def superEggDrop(self, K, N): self.memo = {} return self.helper(K, N) def helper(self, K, N): if K == 1: return N if N == 0: return 0 if (K, N) in self.memo: return self.memo[(K, N)] res = float("inf") start, end = 1, N while start <= end: mid = start + (end - start) // 2 broken = self.helper(K-1, mid-1) not_broken = self.helper(K, N-mid) if broken > not_broken: end = mid - 1 res = min(res, broken + 1) else: start = mid + 1 res = min(res, not_broken + 1) self.memo[(K, N)] = res return res

887. Super Egg Drop You are given K eggs, and you have access to a building with N floors from 1 to N. Each egg is identical in function, and if an egg breaks, you cannot drop it again. You know that there exists a floor F with 0 <= F <= N such that any egg dropped at a floor higher than F will break, and any egg dropped at or below floor F will not break. Each move, you may take an egg (if you have an unbroken one) and drop it from any floor X (with 1 <= X <= N). Your goal is to know with certainty what the value of F is. What is the minimum number of moves that you need to know with certainty what F is, regardless of the initial value of F? Example 1: Input: K = 1, N = 2 Output: 2 Explanation: Drop the egg from floor 1. If it breaks, we know with certainty that F = 0. Otherwise, drop the egg from floor 2. If it breaks, we know with certainty that F = 1. If it didn't break, then we know with certainty F = 2. Hence, we needed 2 moves in the worst case to know what F is with certainty.

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def totalFruit(self, tree): p1, res = 0, 0 count = collections.Counter() for p2, t in enumerate(tree): count[t] += 1 while len(count) > 2: count[tree[p1]] -= 1 if count[tree[p1]] == 0: del count[tree[p1]] p1 += 1 res = max(res, p2 - p1 +1) return res

904. Fruit Into Baskets In a row of trees, the i-th tree produces fruit with type tree[i]. You start at any tree of your choice, then repeatedly perform the following steps: 1. Add one piece of fruit from this tree to your baskets. If you cannot, stop. 2. Move to the next tree to the right of the current tree. If there is no tree to the right, stop. Note that you do not have any choice after the initial choice of starting tree: you must perform step 1, then step 2, then back to step 1, then step 2, and so on until you stop. You have two baskets, and each basket can carry any quantity of fruit, but you want each basket to only carry one type of fruit each. What is the total amount of fruit you can collect with this procedure? Example 1: Input: [1,2,1] Output: 3 Explanation: We can collect [1,2,1]. Example 4: Input: [3,3,3,1,2,1,1,2,3,3,4] Output: 5 Explanation: We can collect [1,2,1,1,2]. If we started at the first tree or the eighth tree, we would only collect 4 fruits.

Data Structure: Algorithm: Time complexity: Space complexity: def snakesAndLadders(self, board): m, n = len(board), len(board[0]) new_board = [] direction = 1 for i in range(m-1, -1, -1): for j in range(0, n): if direction == -1: new_board.append(board[i][n-1-j]) else: new_board.append(board[i][j]) direction *= -1 q = deque() q.append([0, 0]) print(new_board) while q: pos, step = q.popleft() if pos == (m*n-1): return step for i in range(1, 7): new_pos = pos + i if new_pos >= (m*n) or new_board[new_pos] == 0: continue if new_board[new_pos] == -1: q.append([new_pos, step+1]) if new_board[new_pos] > 0: q.append([new_board[new_pos]-1, step+1]) new_board[new_pos] = 0 return -1

909. Snakes and Ladders On an N x N board, the numbers from 1 to N*N are written boustrophedonically starting from the bottom left of the board, and alternating direction each row. For example, for a 6 x 6 board, the numbers are written as follows: You start on square 1 of the board (which is always in the last row and first column). Each move, starting from square x, consists of the following: You choose a destination square S with number x+1, x+2, x+3, x+4, x+5, or x+6, provided this number is <= N*N.(This choice simulates the result of a standard 6-sided die roll: ie., there are always at most 6 destinations, regardless of the size of the board.) If S has a snake or ladder, you move to the destination of that snake or ladder. Otherwise, you move to S. A board square on row r and column c has a "snake or ladder" if board[r][c] != -1. The destination of that snake or ladder is board[r][c]. Note that you only take a snake or ladder at most once per move: if the destination to a snake or ladder is the start of another snake or ladder, you do not continue moving. (For example, if the board is `[[4,-1],[-1,3]]`, and on the first move your destination square is `2`, then you finish your first move at `3`, because you do not continue moving to `4`.) Return the least number of moves required to reach square N*N. If it is not possible, return -1. Example 1: Input: [ [-1,-1,-1,-1,-1,-1], [-1,-1,-1,-1,-1,-1], [-1,-1,-1,-1,-1,-1], [-1,35,-1,-1,13,-1], [-1,-1,-1,-1,-1,-1], [-1,15,-1,-1,-1,-1] ] Output: 4 Explanation: At the beginning, you start at square 1 [at row 5, column 0]. You decide to move to square 2, and must take the ladder to square 15. You then decide to move to square 17 (row 3, column 5), and must take the snake to square 13. You then decide to move to square 14, and must take the ladder to square 35. You then decide to move to square 36, ending the game. It can be shown that you need at least 4 moves to reach the N*N-th square, so the answer is 4.

input: one matrix output: one integer test cases: 1->2->3->4->5->NULL, m = 2, n = 4 => 1->4->3->2->5->NULL Assumption: No Data Structure: No Algorithm: Iterative Time complexity: O(N) Space complexity: O(1) class Solution(object): def reverseBetween(self, head, m, n): d = ListNode(0) d.next = head prev, curr = d, head for _ in range(m-1): prev = curr curr = curr.next last_node_of_list_1 = prev first_node_of_list_2 = curr prev = curr curr = curr.next for _ in range(m, n): temp = curr.next curr.next = prev prev = curr curr = temp last_node_of_list_2 = prev first_node_of_list_3 = curr last_node_of_list_1.next = last_node_of_list_2 first_node_of_list_2.next = first_node_of_list_3 return d.next

92. Reverse Linked List II Reverse a linked list from position m to n. Do it in one-pass.

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def reorderLogFiles(self, logs): letter_logs = [] digit_logs = [] for log in logs: s = log.split(' ') if s[1][0] in 'abcdefghijklmnopqrstuvwxyz': letter_logs.append([s[1:], log]) else: digit_logs.append(log) res = [] letter_logs.sort() for _, log in letter_logs: res.append(log) return res + digit_logs

937. Reorder Data in Log Files You have an array of logs. Each log is a space delimited string of words. For each log, the first word in each log is an alphanumeric identifier. Then, either: 1. Each word after the identifier will consist only of lowercase letters, or; 2. Each word after the identifier will consist only of digits. We will call these two varieties of logs letter-logs and digit-logs. It is guaranteed that each log has at least one word after its identifier. Reorder the logs so that all of the letter-logs come before any digit-log. The letter-logs are ordered lexicographically ignoring identifier, with the identifier used in case of ties. The digit-logs should be put in their original order. Return the final order of the logs.

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def prisonAfterNDays(self, cells, N): if not cells or N == 0: return cells seen = {} i = 0 fast_forward = False res = [] res.append(cells) while i < N: if tuple(cells) in seen: period = i - seen[tuple(cells)] residule = (N - seen[tuple(cells)])%period return res[seen[tuple(cells)]+residule] else: seen[tuple(cells)] = i temp = [0] * len(cells) temp[0] = temp[len(cells)-1] = 0 for j in range(1, len(cells)-1): temp[j] = int(cells[j-1] == cells[j+1]) cells = temp res.append(temp) i += 1 return cells

957. Prison Cells After N Days There are 8 prison cells in a row, and each cell is either occupied or vacant. Each day, whether the cell is occupied or vacant changes according to the following rules: 1. If a cell has two adjacent neighbors that are both occupied or both vacant, then the cell becomes occupied. 2. Otherwise, it becomes vacant. (Note that because the prison is a row, the first and the last cells in the row can't have two adjacent neighbors.) We describe the current state of the prison in the following way: cells[i] == 1 if the i-th cell is occupied, else cells[i] == 0. Given the initial state of the prison, return the state of the prison after N days (and N such changes described above.) Example 1: Input: cells = [0,1,0,1,1,0,0,1], N = 7 Output: [0,0,1,1,0,0,0,0] Explanation: The following table summarizes the state of the prison on each day: Day 0: [0, 1, 0, 1, 1, 0, 0, 1] Day 1: [0, 1, 1, 0, 0, 0, 0, 0] Day 2: [0, 0, 0, 0, 1, 1, 1, 0] Day 3: [0, 1, 1, 0, 0, 1, 0, 0] Day 4: [0, 0, 0, 0, 0, 1, 0, 0] Day 5: [0, 1, 1, 1, 0, 1, 0, 0] Day 6: [0, 0, 1, 0, 1, 1, 0, 0] Day 7: [0, 0, 1, 1, 0, 0, 0, 0] Example 2: Input: cells = [1,0,0,1,0,0,1,0], N = 1000000000 Output: [0,0,1,1,1,1,1,0]

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def kClosest(self, points, K): res = [] minheap = [] heapq.heapify(minheap) for i in range(len(points)): d = points[i][0]**2 + points[i][1]**2 heappush(minheap, (d, points[i])) for _ in range(K): res.append(minheap[0][1]) heappop(minheap) return res

973. K Closest Points to Origin We have a list of points on the plane. Find the K closest points to the origin (0, 0). (Here, the distance between two points on a plane is the Euclidean distance.) You may return the answer in any order. The answer is guaranteed to be unique (except for the order that it is in.) Example 1: Input: points = [[1,3],[-2,2]], K = 1 Output: [[-2,2]] Example 2: Input: points = [[3,3],[5,-1],[-2,4]], K = 2 Output: [[3,3],[-2,4]] (The answer [[-2,4],[3,3]] would also be accepted.)

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def sortedSquares(self, A): p1, p2 = 0, len(A)-1 res = [0 for i in range(len(A))] i = p2 while p1 <= p2: if A[p1]**2 > A[p2]**2: res[i] = A[p1]**2 p1 += 1 else: res[i] = A[p2]**2 p2 -= 1 i -= 1 return res

977. Squares of a Sorted Array Given an array of integers A sorted in non-decreasing order, return an array of the squares of each number, also in sorted non-decreasing order. Example 1: Input: [-4,-1,0,3,10] Output: [0,1,9,16,100] Example 2: Input: [-7,-3,2,3,11] Output: [4,9,9,49,121]

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def intervalIntersection(self, A, B): i, j = 0, 0 res = [] while i < len(A) and j < len(B): if A[i][0]<=B[j][0]<=A[i][1] or B[j][0]<=A[i][0]<=B[j][1]: start = max(A[i][0], B[j][0]) end = min(A[i][1], B[j][1]) res.append([start, end]) if B[j][1] > A[i][1]: i += 1 else: j += 1 return res

986. Interval List Intersections Given two lists of closed intervals, each list of intervals is pairwise disjoint and in sorted order. Return the intersection of these two interval lists. (Formally, a closed interval [a, b] (with a <= b) denotes the set of real numbers x with a <= x <= b. The intersection of two closed intervals is a set of real numbers that is either empty, or can be represented as a closed interval. For example, the intersection of [1, 3] and [2, 4] is [2, 3].) Example 1: (see image) Input: A = [[0,2],[5,10],[13,23],[24,25]], B = [[1,5],[8,12],[15,24],[25,26]] Output: [[1,2],[5,5],[8,10],[15,23],[24,24],[25,25]]

Data Structure: Algorithm: Time complexity: Space complexity: class Solution(object): def orangesRotting(self, grid): if not grid or not grid[0]: return -1 q = deque() m, n = len(grid), len(grid[0]) direction = [[1, 0], [0, 1], [-1, 0], [0, -1]] steps = 0 for i in range(m): for j in range(n): if grid[i][j] == 2: q.append([i, j, 0]) while q: x, y, steps = q.popleft() for d in direction: new_x, new_y = x + d[0], y + d[1] if 0<=new_x<m and 0<=new_y<n and grid[new_x][new_y] == 1: grid[new_x][new_y] = 2 q.append([new_x, new_y, steps+1]) for i in range(m): for j in range(n): if grid[i][j] == 1: return -1 return steps

994. Rotting Oranges In a given grid, each cell can have one of three values: the value 0 representing an empty cell; the value 1 representing a fresh orange; the value 2 representing a rotten orange. Every minute, any fresh orange that is adjacent (4-directionally) to a rotten orange becomes rotten. Return the minimum number of minutes that must elapse until no cell has a fresh orange. If this is impossible, return -1 instead. Example 1: (see image) Input: [[2,1,1],[1,1,0],[0,1,1]] Output: 4

input: one Tree node output: an integer test cases: Assumption: No Data Structure: No Algorithm: BFS Time complexity: O(N) Space complexity: O(N) class Solution(object): def maxDepth(self, root): if root is None: return 0 q = deque() q.append(root) res = 0 while q: res += 1 size = len(q) for _ in range(size): node = q.popleft() if node.left: q.append(node.left) if node.right: q.append(node.right) return res

104. Maximum Depth of Binary Tree Given a binary tree, find its maximum depth. The maximum depth is the number of nodes along the longest path from the root node down to the farthest leaf node.

Assumption: 1. exactly one solution 2. not use the same element twice Data Structure: hashtable: maintain a mapping of each element in the array to its index Algorithm: Two-pass Hash Table 1. In the first iteration, add each element's value and its index to the table. 2. In the second iteration, check if each element's complement (target - nums[i]) exists in the table. 3. Beware that the complement must not be nums[i] itself. Time complexity: O(n) Space complexity: O(n) def twoSum(self, nums, target): hashmap = {} for i, n in enumerate(nums): hashmap[n] = i for i, n in enumerate(nums): m = target - n if m in hashmap and i != hashmap[m]: return [i, hashmap[m]] return [-1, -1]

1. Two Sum Given an array of integers, return indices of the two numbers such that they add up to a specific target. [2, 7, 11, 15], 9 => [0, 1]

input: two strings output: boolean test case: 'aa', 'a*' => True 'ab', '.*' = > True 'aab', 'c*a*b' => True Assumption: 1. both string could be empty 2. contains only lowercase Data Structure: 2-d array DP[i][j]: if s[:i] and p[:j] matches Algorithm: Dynamic Programming 1. Transition function: if s[i-1] == p[j-1] or p[j-1] == '*' DP[i][j] = DP[i-1][j-1] if p[j-1] == '#' and j >= 2, DP[i][j] = DP[i][j-2] or (p[j-2] == '.' or s[i-1] == p[j-2]) 2. Base cases: DP[0][0] = True DP[0][j] = DP[0][j-2] if s[j-1] == '*' Time complexity: O(mn) Space complexity: O(mn) class Solution(object): def isMatch(self, s, p): n = len(s) m = len(p) dp = [[False]*(m+1) for _ in range(n+1)] dp[0][0] = True for j in range(1, m+1): if p[j-1] == '*' and j >= 2: dp[0][j] = dp[0][j-2] for i in range(1, n+1): for j in range(1, m+1): if s[i-1] == p[j-1] or p[j-1] == '.': dp[i][j] = dp[i-1][j-1] if p[j-1] == '*' and j >= 2: dp[i][j] = dp[i][j-2] or (dp[i-1][j] and (s[i-1] == p[j-2] or p[j-2] == '.')) return dp[n][m]

10. Regular Expression Matching Given an input string (s) and a pattern (p), implement regular expression matching with support for '.' and '*'. '.' Matches any single character. '*' Matches zero or more of the preceding element.

input: one Tree node output: True of False test cases: Assumption: No Data Structure: No Algorithm: Recursion Time complexity: O(N) Space complexity: O(log N) class Solution(object): def isSymmetric(self, root): if root is None: return True return self.traverse(root.left, root.right) def traverse(self, left, right): if left is None and right is None: return True if left is None or right is None or left.val != right.val: return False return self.traverse(left.left, right.right) and self.traverse(left.right, right.left)

101. Symmetric Tree Given a binary tree, check whether it is a mirror of itself (ie, symmetric around its center).

input: one Tree node output: a list of arrays test cases: Assumption: No Data Structure: No Algorithm: BFS Time complexity: O(N) Space complexity: O(N) class Solution(object): def levelOrder(self, root): if root is None: return [] q = deque() q.append(root) res = deque() while q: size = len(q) level = [] for _ in range(size): node = q.popleft() level.append(node.val) if node.left: q.append(node.left) if node.right: q. append(node.right) res.append(level) return res

102. Binary Tree Level Order Traversal Given a binary tree, return the level order traversal of its nodes' values. (ie, from left to right, level by level).

input: one Tree node output: a list of arrays test cases: Assumption: No Data Structure: No Algorithm: BFS Time complexity: O(N) Space complexity: O(N) class Solution(object): def zigzagLevelOrder(self, root): if root is None: return [] q = deque() q.append(root) res = deque() left2right = 1 while q: level = [] for _ in range(len(q)): node = q.popleft() level.append(node.val) if node.left: q.append(node.left) if node.right: q. append(node.right) res.append(level[::left2right]) left2right *= -1 return res

103. Binary Tree Zigzag Level Order Traversal Given a binary tree, return the zigzag level order traversal of its nodes' values. (ie, from left to right, then right to left for the next level and alternate between).

input: one Tree node output: a list of arrays test cases: Assumption: No Data Structure: No Algorithm: BFS Time complexity: O(N) Space complexity: O(N) class Solution(object): def levelOrderBottom(self, root): if root is None: return [] q = deque() q.append(root) res = deque() while q: level = [] for _ in range(len(q)): node = q.popleft() level.append(node.val) if node.left: q.append(node.left) if node.right: q. append(node.right) res.appendleft(level) return res

107. Binary Tree Level Order Traversal II Given a binary tree, return the bottom-up level order traversal of its nodes' values. (ie, from left to right, level by level from leaf to root).

input: one Tree node output: True or False test cases: Assumption: No Data Structure: No Algorithm: Recursion Time complexity: O(N log N) Space complexity: O(N) class Solution(object): def isBalanced(self, root): if root is None: return True left_height = self.get_height(root.left) right_height = self.get_height(root.right) if abs(left_height - right_height) <= 1: return (self.isBalanced(root.left) and self.isBalanced(root.right)) else: return False def get_height(self, root): if root is None: return 0 return 1 + max(self.get_height(root.left), self.get_height(root.right))

110. Balanced Binary Tree Given a binary tree, determine if it is height-balanced. For this problem, a height-balanced binary tree is defined as: a binary tree in which the left and right subtrees of every node differ in height by no more than 1.

input: one Tree node output: Integer test cases: Assumption: No Data Structure: No Algorithm: BFS Time complexity: O(N) Space complexity: O(N) class Solution(object): def minDepth(self, root): if root is None: return 0 q = deque() q.append(root) res = 1 while q: q_size = len(q) for _ in range(q_size): curr = q.popleft() if curr.left is None and curr.right is None: return res if curr.left is not None: q.append(curr.left) if curr.right is not None: q.append(curr.right) res += 1 return res

111. Minimum Depth of Binary Tree Given a binary tree, find its minimum depth. The minimum depth is the number of nodes along the shortest path from the root node down to the nearest leaf node.

input: one Tree node output: True or False test cases: Assumption: No Data Structure: No Algorithm: Recursion Time complexity: O(N) Space complexity: O(N) class Solution(object): def hasPathSum(self, root, sum): if root is None: return False if not root.left and not root.right and root.val == sum: return True return self.hasPathSum(root.left, sum-root.val) or self.hasPathSum(root.right, sum-root.val)

112. Path Sum Given a binary tree and a sum, determine if the tree has a root-to-leaf path such that adding up all the values along the path equals the given sum.

input: one Tree node output: one Tree node test cases: Assumption: No Data Structure: No Algorithm: BFS Time complexity: O(N) Space complexity: O(N) class Solution(object): def connect(self, root): if not root: return root q = deque() q.append(root) while q: size = len(q) for i in range(size): node = q.popleft() if i < (size - 1): node.next = q[0] if node.left: q.append(node.left) if node.right: q.append(node.right) return root

116. Populating Next Right Pointers in Each Node You are given a perfect binary tree where all leaves are on the same level, and every parent has two children.

Algorithm: Time complexity: Space complexity: class Solution(object): def generate(self, numRows): if numRows < 1: return [] res = [[1]*(i+1) for i in range(numRows)] for i in range(2, numRows): for j in range(1, i): res[i][j] = res[i-1][j-1] + res[i-1][j] return res

118. Pascal's Triangle Given a non-negative integer numRows, generate the first numRows of Pascal's triangle.

Algorithm: Time complexity: Space complexity: class Solution(object): def getRow(self, rowIndex): if rowIndex < 0: return [] if rowIndex == 0: return [1] res = [1, 1] for i in range(2, rowIndex+1): last = res res = [1 for j in range(i+1)] for j in range(1, i): res[j] = last[j-1] + last[j] return res

119. Pascal's Triangle II Given a non-negative index k where k ≤ 33, return the kth index row of the Pascal's triangle. Note that the row index starts from 0.

input: one Matrix output: one integer test cases: Assumption: No Data Structure: No Algorithm: Dynamic Programming Time complexity: O(N) Space complexity: O(N) class Solution(object): def minimumTotal(self, triangle): DP = [[0]*(i+1) for i in range(len(triangle))] DP[0][0] = triangle[0][0] for i in range(1, len(triangle)): DP[i][0] = DP[i-1][0] + triangle[i][0] DP[i][i] = DP[i-1][i-1] + triangle[i][i] for i in range(1, len(triangle)): for j in range(1, i): DP[i][j] = min(DP[i-1][j-1], DP[i-1][j]) + triangle[i][j] return min(DP[-1][:])

120. Triangle Given a triangle, find the minimum path sum from top to bottom. Each step you may move to adjacent numbers on the row below.

input: one array output: one integer test cases: Assumption: No Data Structure: a 2-D array DP[i][0]: how much money we gain from day 1 to day i when we don't have the stock DP[i][1]: how much money we gain from day 1 to day i when we have the stock Algorithm: Dynamic Programming Transition Function: DP[i][0] = max(DP[i-1][0], DP[i-1][1] + prices[i-1]) DP[i][1] = max(DP[i-1][1], -prices[i-1]) Base Cases: DP[0][0] = 0, DP[0][1] = -inf Time complexity: O(N) Space complexity: O(N) class Solution(object): def maxProfit(self, prices): n = len(prices) dp = [[0] * 2 for _ in range(n+1)] dp[0][0] = 0 dp[0][1] = -float('inf') for i in range(1, n+1): dp[i][0] = max(dp[i-1][0], dp[i-1][1] + prices[i-1]) dp[i][1] = max(dp[i-1][1], -prices[i-1]) return dp[n][0]

121. Best Time to Buy and Sell Stock Say you have an array for which the ith element is the price of a given stock on day i. If you were only permitted to complete at most one transaction (i.e., buy one and sell one share of the stock), design an algorithm to find the maximum profit. Note that you cannot sell a stock before you buy one.

input: one array output: one integer test cases: Assumption: No Data Structure: a 2-D array DP[i][0]: how much money we gain from day 1 to day i when we don't have the stock DP[i][1]: how much money we gain from day 1 to day i when we have the stock Algorithm: Dynamic Programming Transition Function: DP[i][0] = max(DP[i-1][0], DP[i-1][1] + prices[i-1]) DP[i][1] = max(DP[i-1][1], DP[i-1][0] -prices[i-1]) Base Cases: DP[0][0] = 0, DP[0][1] = -inf Time complexity: O(N) Space complexity: O(N) class Solution(object): def maxProfit(self, prices): n = len(prices) dp = [[0] * 2 for _ in range(n+1)] dp[0][0] = 0 dp[0][1] = -float('inf') for i in range(1, n+1): dp[i][0] = max(dp[i-1][0], dp[i-1][1] + prices[i-1]) dp[i][1] = max(dp[i-1][1], dp[i-1][0] -prices[i-1]) return dp[n][0]

122. Best Time to Buy and Sell Stock II Say you have an array prices for which the ith element is the price of a given stock on day i. Design an algorithm to find the maximum profit. You may complete as many transactions as you like (i.e., buy one and sell one share of the stock multiple times).

input: one array output: one integer test cases: Assumption: No Data Structure: a 3-D array DP[i][k][0]: how much money we gain from day 1 to day i when we don't have the stock after k transitions DP[i][k][1]: how much money we gain from day 1 to day i when we have the stock after k transitions Algorithm: Dynamic Programming Transition Function: DP[i][k][0] = max(DP[i-1][k][0], DP[i-1][k][1] + prices[i-1]) DP[i][k][1] = max(DP[i-1][k][1], DP[i-1][k-1][0] -prices[i-1]) Base Cases: DP[0][0] = 0, DP[0][1] = -inf Time complexity: O(N) Space complexity: O(N) class Solution(object): def maxProfit(self, prices): n = len(prices) dp = [[[0]*2 for _ in range(3)] for _ in range(n+1)] for k in range(0, 3): dp[0][k][0] = 0 dp[0][k][1] = -float('inf') for i in range(0, n): dp[i][0][0] = 0 dp[i][0][1] = -float('inf') for i in range(1, n+1): for k in range(1, 3): dp[i][k][0] = max(dp[i-1][k][0], dp[i-1][k][1] + prices[i-1]) dp[i][k][1] = max(dp[i-1][k][1], dp[i-1][k-1][0] - prices[i-1]) return dp[n][2][0]

123. Best Time to Buy and Sell Stock III Say you have an array for which the ith element is the price of a given stock on day i. Design an algorithm to find the maximum profit. You may complete at most two transactions.

input: one Tree Node output: one integer test cases: Assumption: No Data Structure: No Algorithm: Recursion Recursion returns the max sum of subtree Use global variable to get the max path Time complexity: O(N) Space complexity: O(N) class Solution(object): def __init__(self): self.path_max = -float("inf") def maxPathSum(self, root): self.dfs(root) return self.path_max def dfs(self, root): if root is None: return 0 val = root.val curr_sum = val left = self.dfs(root.left) right = self.dfs(root.right) curr_sum += max(0, left) + max(0, right) self.path_max = max(self.path_max, curr_sum) return max(val, max(left+val, right+val))

124. Binary Tree Maximum Path Sum Given a non-empty binary tree, find the maximum path sum. For this problem, a path is defined as any sequence of nodes from some starting node to any node in the tree along the parent-child connections. The path must contain at least one node and does not need to go through the root.

input: one Tree Node output: one integer test cases: Assumption: No Data Structure: hashmap to record the tree structure h[child] = parent Algorithm: BFS&DFS Use BFS to find the shortest path Use DFS to backtrack the path Time complexity: O(N) Space complexity: O(N) class Solution(object): def __init__(self): self.res = [] self.memo = set() def findLadders(self, beginWord, endWord, wordList): if endWord not in wordList: return [] wordList = set(wordList) hashmap = {} hashmap[beginWord] = [] for word in wordList: hashmap[word] = [] n = len(beginWord) q = set() q.add(beginWord) while len(q) > 0: pre_q = q q = set() for word in pre_q: if word == endWord: hashmap[beginWord] = [] self.dfs([], endWord, hashmap) break for i in range(n): for c in 'abcdefghijklmnopqrstuvwxyz': if c == word[i]: continue new_word = word[:i] + c + word[i+1:] if new_word in wordList: q.add(new_word) hashmap[new_word].append(word) for word in q: if word != beginWord: wordList.remove(word) return self.res def dfs(self, path, word, hashmap): if len(hashmap[word]) == 0: self.res.append([word] + path[::-1]) return path.append(word) for w in hashmap[word]: self.dfs(path, w, hashmap) path.pop()

126. Word Ladder II Given two words (beginWord and endWord), and a dictionary's word list, find all shortest transformation sequence(s) from beginWord to endWord, such that: Only one letter can be changed at a time Each transformed word must exist in the word list. Note that beginWord is not a transformed word.

input: one Tree Node output: one integer test cases: Assumption: No Data Structure: No Algorithm: BFS Time complexity: O(N) Space complexity: O(N) class Solution(object): def ladderLength(self, beginWord, endWord, wordList): if endWord not in wordList: return 0 wordList = set(wordList) n = len(beginWord) q = deque() q.append((beginWord, 1)) while q: word, step = q.popleft() if word == endWord: return step for i in range(n): for c in 'abcdefghijklmnopqrstuvwxyz': new_word = word[:i] + c + word[i+1:] if new_word in wordList: q.append((new_word, step+1)) wordList.remove(new_word) return 0

127. Word Ladder Given two words (beginWord and endWord), and a dictionary's word list, find the length of shortest transformation sequence from beginWord to endWord, such that: Only one letter can be changed at a time. Each transformed word must exist in the word list.

input: one Tree Node output: one integer test cases: Assumption: No Data Structure: No Algorithm: DFS Time complexity: O(N) Space complexity: O(N) class Solution(object): def sumNumbers(self, root): return self.dfs(root, 0) def dfs(self, root, sum): if root is None: return 0 sum = root.val + 10 * sum if not root.left and not root.right: return sum else: return self.dfs(root.left, sum) + self.dfs(root.right, sum)

129. Sum Root to Leaf Numbers Given a binary tree containing digits from 0-9 only, each root-to-leaf path could represent a number. An example is the root-to-leaf path 1->2->3 which represents the number 123. Find the total sum of all root-to-leaf numbers.

input: one Tree Node output: one Tree Node test cases: Assumption: No Data Structure: No Algorithm: DFS with memo Time complexity: O(N) Space complexity: O(N) class Solution(object): def cloneGraph(self, node): memo = {} return self.dfs(node, memo) def dfs(self, node, memo): if not node: return None if node in memo: return memo[node] new_node = Node(node.val, []) memo[node] = new_node for n in node.neighbors: temp = self.dfs(n, memo) if temp: memo[node].neighbors.append(temp) return new_node

133. Clone Graph Given a reference of a node in a connected undirected graph. Return a deep copy (clone) of the graph. Each node in the graph contains a val (int) and a list (List[Node]) of its neighbors.

input: one array output: one integer test cases: Assumption: No Data Structure: No Algorithm: Use DFS and in-order traverse to flatten the BST Time complexity: O(n) Space complexity: O(n) class BSTIterator(object): def __init__(self, root): self.res = [] self.dfs(root) def dfs(self, root): if root == None: return self.dfs(root.left) self.res.append(root.val) self.dfs(root.right) def next(self): return self.res.pop(0) def hasNext(self): return len(self.res) > 0

173. Binary Search Tree Iterator Implement an iterator over a binary search tree (BST). Your iterator will be initialized with the root node of a BST. Calling next() will return the next smallest number in the BST.

input: one array output: one integer test cases: Assumption: No Data Structure: No Algorithm: One Pass It's impossible to perform the road trip if sum(gas) < sum(cost). In this situation the answer is -1. It's impossible to start at a station i if gas[i] - cost[i] < 0, because then there is not enough gas in the tank to travel to i + 1 station. Time complexity: O(N) Space complexity: O(N) class Solution(object): def canCompleteCircuit(self, gas, cost): total = 0 curr_sum = 0 res = 0 for i in range(len(gas)): total += gas[i] - cost[i] curr_sum += gas[i] - cost[i] if curr_sum < 0: res = i + 1 curr_sum = 0 if total >= 0: return res return -1

134. Gas Station There are N gas stations along a circular route, where the amount of gas at station i is gas[i]. You have a car with an unlimited gas tank and it costs cost[i] of gas to travel from station i to its next station (i+1). You begin the journey with an empty tank at one of the gas stations. Return the starting gas station's index if you can travel around the circuit once in the clockwise direction, otherwise return -1.

input: one array output: one integer test cases: Assumption: No Data Structure: No Algorithm: Recursive 1. Start traversing the graph from head node. 2. If we already have a cloned copy of the current node in the visited dictionary, we use the cloned node reference. 3. If we don't have a cloned copy in the visited dictionary, we create a new node and add it to the visited dictionary. 4. We then make two recursive calls, one using the random pointer and the other using next pointer. The diagram from step 1, shows random and next pointers in red and blue color respectively. Essentially we are making recursive calls for the children of the current node. In this implementation, the children are the nodes pointed by the random and the next pointers. Time complexity: O(N) Space complexity: O(N) class Solution(object): def __init__(self): self.memo = {} def copyRandomList(self, head): if head is None: return None if head in self.memo: return self.memo[head] new_node = Node(head.val) self.memo[head] = new_node new_node.next = self.copyRandomList(head.next) new_node.random = self.copyRandomList(head.random) return new_node

138. Copy List with Random Pointer A linked list is given such that each node contains an additional random pointer which could point to any node in the list or null. Return a deep copy of the list.

input: one string, one array of strings output: Tree or False test cases: s = "leetcode", wordDict = ["leet", "code"] => True Assumption: The same word in the dictionary may be reused multiple times in the segmentation. You may assume the dictionary does not contain duplicate words. Data Structure: one 1-D array DP[i]: indication if s[:i] can be segmented Algorithm: Dynamic Programming Time complexity: O(N) Space complexity: O(N) class Solution(object): def wordBreak(self, s, wordDict): dp = [False] * (len(s)+1) dp[0] = True for i in range(1, len(s)+1): for j in range(0, i): if s[j:i] in wordDict and dp[j]: dp[i] = dp[j] break return dp[len(s)]

139. Word Break Given a non-empty string s and a dictionary wordDict containing a list of non-empty words, determine if s can be segmented into a space-separated sequence of one or more dictionary words.

input: one string, one array of strings output: Tree or False test cases: s = "leetcode", wordDict = ["leet", "code"] => True Assumption: The same word in the dictionary may be reused multiple times in the segmentation. You may assume the dictionary does not contain duplicate words. Data Structure: one 1-D array DP[i]: indication if s[:i] can be segmented Algorithm: DFS Time complexity: O(N) Space complexity: O(N) class Solution(object): def wordBreak(self, s, wordDict): res = [] memo = {} return self.dfs(s, res, wordDict, memo) def dfs(self, s, path, wordDict, memo): if len(s) == 0: return [""] if s in memo: return memo[s] res = [] for word in wordDict: if s[:len(word)] != word: continue for r in self.dfs(s[len(word):], res, wordDict, memo): res.append(word + ("" if not r else " ") + r) memo[s] = res return res

140. Word Break II Given a non-empty string s and a dictionary wordDict containing a list of non-empty words, add spaces in s to construct a sentence where each word is a valid dictionary word. Return all such possible sentences.

input: one string, one array of strings output: Tree or False test cases: s = "leetcode", wordDict = ["leet", "code"] => True Assumption: The same word in the dictionary may be reused multiple times in the segmentation. You may assume the dictionary does not contain duplicate words. Data Structure: one 1-D array DP[i]: indication if s[:i] can be segmented Algorithm: DFS Time complexity: O(N) Space complexity: O(N) class Solution(object): def hasCycle(self, head): if head is None: return False slow = head fast = head while fast is not None and fast.next is not None: slow = slow.next fast = fast.next.next if slow == fast: return True return False

141. Linked List Cycle Given a linked list, determine if it has a cycle in it. To represent a cycle in the given linked list, we use an integer pos which represents the position (0-indexed) in the linked list where tail connects to. If pos is -1, then there is no cycle in the linked list.

Algorithm: Time complexity: Space complexity: class Solution(object): def detectCycle(self, head): if head is None: return None slow, fast = head, head cycle = False while fast.next is not None and fast.next.next is not None: slow = slow.next fast = fast.next.next if slow == fast: cycle = True break if not cycle: return None slow = head while slow != fast: slow = slow.next fast = fast.next return slow

142. Linked List Cycle II Given a linked list, return the node where the cycle begins. If there is no cycle, return null. To represent a cycle in the given linked list, we use an integer pos which represents the position (0-indexed) in the linked list where tail connects to. If pos is -1, then there is no cycle in the linked list.

Algorithm: Time complexity: Space complexity: class Solution(object): def preorderTraversal(self, root): if root is None: return [] stack = [] stack.append(root) res = [] while stack: node = stack.pop() res.append(node.val) if node.right: stack.append(node.right) if node.left: stack.append(node.left) return res

144. Binary Tree Preorder Traversal

Algorithm: Time complexity: Space complexity: class Solution(object): def postorderTraversal(self, root): if root is None: return [] stack = [] stack.append(root) res = [] while stack: node = stack.pop() res.insert(0, node.val) if node.left: stack.append(node.left) if node.right: stack.append(node.right) return res

145. Binary Tree Postorder Traversal

input: output: test cases: Assumption: No Data Structure: double linked list - to achieve O(1) insert hashtable - to achieve O(1) search Algorithm: Hashmap + DoubleLinkedList solved with a hashmap that keeps track of the keys and its values in the double linked list. That results in \mathcal{O}(1)O(1) time for put and get operations and allows to remove the first added node in \mathcal{O}(1)O(1) time as well. Time complexity: Space complexity: class ListNode(object): def __init__(self, key=None, val=None): self.key = key self.val = val self.prev = None self.next = None class LRUCache(object): def __init__(self, capacity): self.cap = capacity self.hashmap = {} self.head = ListNode() self.tail = ListNode() self.head.next = self.tail self.tail.prev = self.head def pop(self): node = self.tail.prev self.tail.prev = node.prev node.prev.next = self.tail return node def moveToHead(self, node): node.prev.next = node.next node.next.prev = node.prev temp = self.head.next self.head.next = node node.prev = self.head node.next = temp temp.prev = node def addToHead(self, node): temp = self.head.next self.head.next = node node.prev = self.head node.next = temp temp.prev = node def get(self, key): if key in self.hashmap: node = self.hashmap[key] self.moveToHead(node) return node.val return -1 def put(self, key, value): if key in self.hashmap: node = self.hashmap[key] node.val = value self.moveToHead(node) else: if len(self.hashmap) == self.cap: node = self.pop() del self.hashmap[node.key] new_node = ListNode(key, value) self.addToHead(new_node) self.hashmap[key] = new_node

146. LRU Cache Design and implement a data structure for Least Recently Used (LRU) cache. It should support the following operations: get and put. get(key) - Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1. put(key, value) - Set or insert the value if the key is not already present. When the cache reached its capacity, it should invalidate the least recently used item before inserting a new item. The cache is initialized with a positive capacity.

input: an array output: tuples test cases: [-1, 0, 1, 2, -1, -4] => [[-1, 0, Assumption: Solution must not contain duplicated triplets. Data Structure: hashset: ensure no duplicated triplets in solution Algorithm: Two Pointers 1. Sort the array 2. decrement end-pointer if sum > 0 3. increment start-pointer if sum < 0 Time complexity: O(n) Space complexity: O(n) class Solution(object): def threeSum(self, nums): res = set() nums.sort() for i in range(len(nums)): # if i > 0 and nums[i] == nums[i-1]: continue p1 = i+1 p2 = len(nums)-1 while p1 < p2: triplet = [nums[i], nums[p1], nums[p2]] if sum(triplet) > 0: p2 -= 1 elif sum(triplet) < 0: p1 += 1 else: res.add(tuple(triplet)) p1 += 1 p2 -= 1 return list(res)

15. 3Sum Given an array nums of n integers, are there elements a, b, c in nums such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.

input: one array output: one integer test cases: [3,4,5,1,2] => 1 Assumption: no duplicate exists in the array. Data Structure: No Algorithm: Binary Search Time complexity: O(log N) Space complexity: O(1) class Solution(object): def findMin(self, nums): if len(nums) < 2: return nums[0] start = 0 end = len(nums) - 1 while start + 1 < end: mid = start + (end-start)/2 if nums[mid] <= nums[end]: end = mid else: start = mid return min(nums[start], nums[end])

153. Find Minimum in Rotated Sorted Array Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand. (i.e., [0,1,2,4,5,6,7] might become [4,5,6,7,0,1,2]). Find the minimum element.

input: one array output: one integer test cases: [2,2,2,0,1] => 0 Assumption: The array may contain duplicates. Data Structure: No Algorithm: Binary Search Time complexity: O(log N) Space complexity: O(1) class Solution(object): def findMin(self, nums): if len(nums) < 2: return nums[0] start = 0 end = len(nums) - 1 while start + 1 < end: mid = start + (end-start)/2 if nums[mid] < nums[end]: end = mid elif nums[mid] > nums[end]: start = mid else: end -= 1 return min(nums[start], nums[end])

154. Find Minimum in Rotated Sorted Array II Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand. (i.e., [0,1,2,4,5,6,7] might become [4,5,6,7,0,1,2]). Find the minimum element.

input: output: test cases: Assumption: Data Structure: Two stacks: one stack to store the actual number, another stack to store the current min number Algorithm: Two Stacks Time complexity: O(log N) Space complexity: O(1) class MinStack(object): def __init__(self): self.stack = [] self.min = [] def push(self, x): if self.stack == []: self.min.append(x) else: self.min.append(min(x, self.min[-1])) self.stack.append(x) def pop(self): self.stack.pop() self.min.pop() def top(self): return self.stack[-1] def getMin(self): return self.min[-1]

155. Min Stack Design a stack that supports push, pop, top, and retrieving the minimum element in constant time. push(x) -- Push element x onto stack. pop() -- Removes the element on top of the stack. top() -- Get the top element. getMin() -- Retrieve the minimum element in the stack.

input: one array output: an index test cases: [1,2,3,1] => 2 Assumption: The array may contain multiple peaks, in that case return the index to any one of the peaks is fine. Data Structure: No Algorithm: Binary Search Time complexity: O(log N) Space complexity: O(1) class Solution(object): def findPeakElement(self, nums): if nums == []: return None if len(nums) < 2: return 0 start = 0 end = len(nums) - 1 while start + 1 < end: middle = start + (end - start) / 2 if nums[middle] < nums[middle+1]: start = middle else: end = middle if nums[start] >= nums[end]: return start return end

162. Find Peak Element A peak element is an element that is greater than its neighbors. Given an input array nums, where nums[i] ≠ nums[i+1], find a peak element and return its index.

Algorithm: Time complexity: Space complexity: class Solution(object): def compareVersion(self, version1, version2): v1 = version1.split('.') v2 = version2.split('.') v1_num = deque() v2_num = deque() for v in v1: v1_num.append(int(v)) for v in v2: v2_num.append(int(v)) while v1_num and v2_num: num_1 = v1_num.popleft() num_2 = v2_num.popleft() if num_1 > num_2: return 1 if num_1 < num_2: return -1 while v1_num and v1_num[0] == 0: v1_num.popleft() while v2_num and v2_num[0] == 0: v2_num.popleft() if len(v1_num) > len(v2_num): return 1 if len(v1_num) < len(v2_num): return -1 return 0

165. Compare Version Numbers Compare two version numbers version1 and version2.If version1 > version2 return 1; if version1 < version2 return -1;otherwise return 0. You may assume that the version strings are non-empty and contain only digits and the . character. The . character does not represent a decimal point and is used to separate number sequences. For instance, 2.5 is not "two and a half" or "half way to version three", it is the fifth second-level revision of the second first-level revision.

input: one array output: one integer test cases: [3,2,3] => 3 Assumption: the array is non-empty and the majority element always exist in the array. Data Structure: hashmap: to store the counts of each element Algorithm: Binary Search Time complexity: O(n) Space complexity: O(n) class Solution(object): def majorityElement(self, nums): counts = dict() for num in nums: counts[num] = counts.get(num, 0) + 1 return max(counts, key = counts.get)

169. Majority Element Given an array of size n, find the majority element. The majority element is the element that appears more than ⌊ n/2 ⌋ times.

input: one matrix output: one integer test cases: Assumption: No Data Structure: a 2-D array DP[i][j]: indicates the minimal health points that the knight would need, starting from the corresponding dungeon cell dungeon[row][col], in order to reach the destination. Algorithm: Dynamic programming Transition Function: DP[i][j] = max(1, min(DP[i+1][j], DP[i][j+1]) - dungeon[i][j]) Base Case: DP[m][n-1] = 1, DP[m][:] = inf, DP[:][n]= inf Time complexity: O(n) Space complexity: O(n) class BSTIterator(object): def __init__(self, root): self.res = [] self.dfs(root) def dfs(self, root): if root == None: return self.dfs(root.left) self.res.append(root.val) self.dfs(root.right) def next(self): return self.res.pop(0) def hasNext(self): return len(self.res) > 0

174. Dungeon Game The demons had captured the princess (P) and imprisoned her in the bottom-right corner of a dungeon. The dungeon consists of M x N rooms laid out in a 2D grid. Our valiant knight (K) was initially positioned in the top-left room and must fight his way through the dungeon to rescue the princess. The knight has an initial health point represented by a positive integer. If at any point his health point drops to 0 or below, he dies immediately. Some of the rooms are guarded by demons, so the knight loses health (negative integers) upon entering these rooms; other rooms are either empty (0's) or contain magic orbs that increase the knight's health (positive integers). In order to reach the princess as quickly as possible, the knight decides to move only rightward or downward in each step.

input: one array output: one integer test cases: Assumption: No Data Structure: a 3-D array DP[i][k][0]: how much money we gain from day 1 to day i when we don't have the stock after k transitions DP[i][k][1]: how much money we gain from day 1 to day i when we have the stock after k transitions Algorithm: Dynamic Programming Transition Function: DP[i][k][0] = max(DP[i-1][k][0], DP[i-1][k][1] + prices[i-1]) DP[i][k][1] = max(DP[i-1][k][1], DP[i-1][k-1][0] -prices[i-1]) Base Cases: DP[0][0] = 0, DP[0][1] = -inf Time complexity: O(N) Space complexity: O(N) class Solution(object): def maxProfit(self, k, prices): n = len(prices) m = k if (m > n/2): return self.maxProfit_Inf(prices) dp = [[[0]*2 for _ in range(m+1)] for _ in range(n+1)] for k in range(0, m+1): dp[0][k][0] = 0 dp[0][k][1] = -float('inf') for i in range(0, n): dp[i][0][0] = 0 dp[i][0][1] = -float('inf') for i in range(1, n+1): for k in range(1, m+1): dp[i][k][0] = max(dp[i-1][k][0], dp[i-1][k][1] + prices[i-1]) dp[i][k][1] = max(dp[i-1][k][1], dp[i-1][k-1][0] - prices[i-1]) return dp[n][m][0] def maxProfit_Inf(self, prices): n = len(prices) dp = [[0] * 2 for _ in range(n+1)] dp[0][0] = 0 dp[0][1] = -float('inf') for i in range(1, n+1): dp[i][0] = max(dp[i-1][0], dp[i-1][1] + prices[i-1]) dp[i][1] = max(dp[i-1][1], dp[i-1][0] -prices[i-1]) return dp[n][0]

188. Best Time to Buy and Sell Stock IV Say you have an array for which the i-th element is the price of a given stock on day i. Design an algorithm to find the maximum profit. You may complete at most k transactions.

input: one array output: None test cases: Assumption: No Data Structure: No Algorithm: Reverse Time complexity: O(N) Space complexity: O(N) class Solution(object): def reverse(self, nums, start, end): while start < end: nums[start], nums[end] = nums[end], nums[start] start += 1 end -= 1 def rotate(self, nums, k): n = len(nums) k = k%n self.reverse(nums, 0, n-1) self.reverse(nums, 0, k-1) self.reverse(nums, k, n-1)

189. Rotate Array Given an array, rotate the array to the right by k steps, where k is non-negative.

input: one linked list, one integer output: one linked list test cases: 1->2->3->4->5, 2 => 1->2->3->5 Assumption: n is always valid Data Structure: No Algorithm: Fast & Slow Pointers Fast pointer is n+1 step ahead of slow point Time complexity: O(L) Space complexity: O(1) class Solution(object): def removeNthFromEnd(self, head, n): temp = ListNode() temp.next = head slow, fast, prev = head, head, temp for _ in range(n): fast = fast.next while fast is not None: prev = slow slow = slow.next fast = fast.next node = slow.next prev.next = node return temp.next

19. Remove Nth Node From End of List Given a linked list, remove the n-th node from the end of list and return its head.

input: one array output: one integer test cases: Assumption: No Data Structure: a 1-D array DP[i]: the max money robber from house[:i] Algorithm: Dynamic Programming Transition Function: DP[i] = max(DP[i-1], nums[i-1] + DP[i-2]) Base Cases: DP[0] = 0, DP[1] Time complexity: O(N) Space complexity: O(1) class Solution(object): def rob(self, nums): n = len(nums) if n == 0: return 0 if n == 1: return nums[0] dp = [0] * (n+1) dp[0] = 0 dp[1] = nums[0] for i in range(1, n+1): dp[i] = max(dp[i-1], nums[i-1] + dp[i-2]) return dp[n]

198. House Robber You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed, the only constraint stopping you from robbing each of them is that adjacent houses have security system connected and it will automatically contact the police if two adjacent houses were broken into on the same night. Given a list of non-negative integers representing the amount of money of each house, determine the maximum amount of money you can rob tonight without alerting the police.

input: two linked list output: one linked list test case: (2->4->3) + (5->6->4) => (7->0->8) (0->1) + (0->1->2) => (0->2->2) () + (0->1) => (0->1) (9->9) + (1) => (0->0->1) Assumption: not have leading zero Data Structure: linked list Algorithm: Elementary Math 1. Create dummy head to deal with head's value 2. Create carry to store summing overflow 3. loop through l1 and l2: sum digital, create new node, update carry. Time complexity: O(max(m, n)) Space complexity: O(max(m, n)) def addTwoNumbers(self, l1, l2): res = ListNode(0) prev = res val = 0 while l1 or l2 or val == 1: if l1: val += l1.val l1 = l1.next if l2: val += l2.val l2 = l2.next curr = ListNode(val % 10) val /= 10 prev.next = curr prev = curr return res.next

2. Add Two Numbers You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order and each of their nodes contain a single digit. Add the two numbers and return it as a linked list.

Time complexity: Space complexity: class Solution(object): def numIslands(self, grid): res = 0 self.direction = [[-1, 0], [1, 0], [0, -1], [0, 1]] for i in range(len(grid)): for j in range(len(grid[0])): if grid[i][j] == '1': self.dfs(grid, i, j) res += 1 return res def dfs(self, grid, i, j): grid[i][j] = '0' for d in self.direction: new_i = i + d[0] new_j = j + d[1] if 0<=new_i<len(grid) and 0<=new_j<len(grid[0]) and grid[new_i][new_j] == '1': self.dfs(grid, new_i, new_j) return

200. Number of Islands Given a 2d grid map of '1's (land) and '0's (water), count the number of islands. An island is surrounded by water and is formed by connecting adjacent lands horizontally or vertically. You may assume all four edges of the grid are all surrounded by water.

input: integer output: True or False test cases: 19 -> True Assumption: Data Structure: No Algorithm: Fast & Slow Pointers Fast pointer is 1 step ahead of slow point Time complexity: O(L) Space complexity: O(1) class Solution(object): def isHappy(self, n): slow = n fast = self.squareSum(n) while slow != fast: slow = self.squareSum(slow) fast = self.squareSum(self.squareSum(fast)) if slow == 1 or fast == 1: return True return slow == 1 def squareSum(self, n): res = 0 while n > 0: res += (n%10) * (n%10) n //= 10 return res

202. Happy Number Write an algorithm to determine if a number n is "happy". A happy number is a number defined by the following process: Starting with any positive integer, replace the number by the sum of the squares of its digits, and repeat the process until the number equals 1 (where it will stay), or it loops endlessly in a cycle which does not include 1. Those numbers for which this process ends in 1 are happy numbers. Return True if n is a happy number, and False if not.

Time complexity: Space complexity: class Solution(object): def removeElements(self, head, val): dummy = ListNode() dummy.next = head prev = dummy curr = head while curr: if curr.val == val: prev.next = curr.next else: prev = curr curr = curr.next return dummy.next

203. Remove Linked List Elements Remove all elements from a linked list of integers that have value val.

Time complexity: Space complexity: class Solution(object): def reverseList(self, head): if head is None or head.next is None: return head last = self.reverseList(head.next) head.next.next = head head.next = None return last

206. Reverse Linked List Reverse a singly linked list.

input: one integer, one list of arrays output: True or False test cases: numCourses = 2, prerequisites = [[1,0]] -> True Assumption: Data Structure: One hashmap: to represent the graph One hashmap: to record the in-degree of each node Algorithm: Topological Sort to find a global order for all nodes in a DAG (Directed Acyclic Graph) with regarding to their dependencies. Time complexity: O(V + E) Space complexity: O(V + E) class Solution(object): def canFinish(self, numCourses, prerequisites): if numCourses < 1: return False res = [] hashmap_graph = {i: [] for i in range(numCourses)} hashmap_degree = {i: 0 for i in range(numCourses)} for child, parent in prerequisites: hashmap_graph[parent].append(child) hashmap_degree[child] += 1 q = deque() for key in hashmap_degree: if hashmap_degree[key] == 0: q.append(key) while q: node = q.pop() res.append(node) for next_node in hashmap_graph[node]: hashmap_degree[next_node] -= 1 if hashmap_degree[next_node] == 0: q.append(next_node) return len(res) == numCourses

207. Course Schedule There are a total of numCourses courses you have to take, labeled from 0 to numCourses-1. Some courses may have prerequisites, for example to take course 0 you have to first take course 1, which is expressed as a pair: [0,1] Given the total number of courses and a list of prerequisite pairs, is it possible for you to finish all courses?

Assumption: Data Structure: class Node(object): def __init__(self): self.children = collections.defaultdict(Node) self.isWord = False class Trie(object): def __init__(self): self.root = Node() def insert(self, word): current = self.root for w in word: current = current.children[w] current.isWord = True def search(self, word): current = self.root for w in word: current = current.children.get(w) if current == None: return False return current.isWord def startsWith(self, prefix): current = self.root for w in prefix: current = current.children.get(w) if current == None: return False return True

208. Implement Trie (Prefix Tree) Implement a trie with insert, search, and startsWith methods.

input: two linked lists output: one linked list test cases: 1->2->4, 1->3->4 => 1->1->2->3->4->4 Assumption: No Data Structure: No Algorithm: Iteration Time complexity: O(L) Space complexity: O(1) class Solution(object): def mergeTwoLists(self, l1, l2): d = ListNode() curr = d while l1 and l2: if l1.val <= l2.val: curr.next = l1 l1 = l1.next else: curr.next = l2 l2 = l2.next curr = curr.next if l1: curr.next = l1 if l2: curr.next = l2 return d.next

21. Merge Two Sorted Lists Merge two sorted linked lists and return it as a new sorted list. The new list should be made by splicing together the nodes of the first two lists.

input: one integer, one list of arrays output: one array test cases: numCourses = 2, prerequisites = [[1,0]] -> [0, 1] Assumption: Data Structure: One hashmap: to represent the graph One hashmap: to record the in-degree of each node Algorithm: Topological Sort to find a global order for all nodes in a DAG (Directed Acyclic Graph) with regarding to their dependencies. Time complexity: O(V + E) Space complexity: O(V + E) class Solution(object): def findOrder(self, numCourses, prerequisites): if numCourses < 1: return [] res = [] hashmap_graph = {i: [] for i in range(numCourses)} hashmap_degree = {i: 0 for i in range(numCourses)} q = deque() for child, parent in prerequisites: hashmap_graph[parent].append(child) hashmap_degree[child] += 1 for node in hashmap_degree: if hashmap_degree[node] == 0: q.append(node) while q: node = q.popleft() res.append(node) for next_node in hashmap_graph[node]: hashmap_degree[next_node] -= 1 if hashmap_degree[next_node] == 0: q.append(next_node) if len(res) == numCourses: return res else: return []

210. Course Schedule II There are a total of n courses you have to take, labeled from 0 to n-1. Some courses may have prerequisites, for example to take course 0 you have to first take course 1, which is expressed as a pair: [0,1] Given the total number of courses and a list of prerequisite pairs, return the ordering of courses you should take to finish all courses. There may be multiple correct orders, you just need to return one of them. If it is impossible to finish all courses, return an empty array.

input: output: test cases: Assumption: Data Structure: Use hashmap to represent Trie Algorithm: Trie & DFS Time complexity: O(V + E) Space complexity: O(V + E) class WordDictionary(object): def __init__(self): self.trie = {} def addWord(self, word): curr = self.trie for w in word: if w not in curr: curr[w] = {} curr = curr[w] curr['#'] = {} return def search(self, word): return self.dfs(word, 0, self.trie) def dfs(self, word, i, trie): if trie == None: return False if i == len(word): if '#' in trie: return True return False if word[i] == '.': for key in trie: if self.dfs(word, i+1, trie[key]): return True else: if word[i] not in trie: return False return self.dfs(word, i+1, trie[word[i]])

211. Add and Search Word - Data structure design Design a data structure that supports the following two operations: void addWord(word) bool search(word) 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.

input: one array output: one integer test cases: Assumption: No Data Structure: a 1-D array DP[i]: the max money robber from house[:i] Algorithm: Dynamic Programming Transition Function: DP[i] = max(DP[i-1], nums[i-1] + DP[i-2]) Base Cases: DP[0] = nums[0], DP[1] = max(nums[:2]) To deal with circle, two option, not robber house 0 or not robber house[-1]. Time complexity: O(N) Space complexity: O(1) class Solution(object): def rob(self, nums): n = len(nums) if n == 0: return 0 if n == 1: return nums[0] if n == 2: return max(nums) return max(self.robRange(nums, 0, n-2), self.robRange(nums, 1, n-1)) def robRange(self, nums, start, end): dp = [0] * len(nums) dp[start] = nums[start] dp[start+1] = max(nums[start:start+2]) for i in range(start+2, end+1): dp[i] = max(dp[i-1], dp[i-2] + nums[i]) return dp[end]

213. House Robber II You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed. All houses at this place are arranged in a circle. That means the first house is the neighbor of the last one. Meanwhile, adjacent houses have security system connected and it will automatically contact the police if two adjacent houses were broken into on the same night. Given a list of non-negative integers representing the amount of money of each house, determine the maximum amount of money you can rob tonight without alerting the police.

input: one array, one integer output: one integer test cases: [3,2,1,5,6,4] and k = 2 => 5 Assumption: No Data Structure: one min heap Algorithm: min heap keep the minheap length as Time complexity: O(N) Space complexity: O(1) class Solution(object): def rob(self, nums): n = len(nums) if n == 0: return 0 if n == 1: return nums[0] if n == 2: return max(nums) return max(self.robRange(nums, 0, n-2), self.robRange(nums, 1, n-1)) def robRange(self, nums, start, end): dp = [0] * len(nums) dp[start] = nums[start] dp[start+1] = max(nums[start:start+2]) for i in range(start+2, end+1): dp[i] = max(dp[i-1], dp[i-2] + nums[i]) return dp[end]

215. Kth Largest Element in an Array Find the kth largest element in an unsorted array. Note that it is the kth largest element in the sorted order, not the kth distinct element.

input: one matrix output: one integer test cases: Assumption: No Data Structure: a 2-D array DP[i][j]: represents the side length of the maximum square whose bottom right corner is the cell with index (i,j) in the original matrix. Algorithm: Dynamic Programming Transition Function: DP[i][j] = min(DP[i-1][j], DP[i-1][j-1], DP[i][j-1] + 1 Time complexity: O(MN) Space complexity: O(MN) class Solution(object): def maximalSquare(self, matrix): if not matrix: return 0 m, n = len(matrix), len(matrix[0]) DP = [[0] * (n+1) for _ in range(m+1)] res = 0 for i in range(1, m+1): for j in range(1, n+1): if matrix[i-1][j-1] == '0': continue DP[i][j] = min(DP[i-1][j], DP[i][j-1], DP[i-1][j-1]) + 1 res = max(res, DP[i][j]**2) return res

221. Maximal Square Given a 2D binary matrix filled with 0's and 1's, find the largest square containing only 1's and return its area.

input: one Tree Node output: one integer test cases: Assumption: No Data Structure: No Algorithm: Recursive Time complexity: O(n) Space complexity: O(n) class Solution(object): def countNodes(self, root): if root == None: return 0 left_node, right_node = root, root h_left, h_right = 0, 0 while left_node is not None: left_node = left_node.left h_left += 1 while right_node is not None: right_node = right_node.right h_right += 1 if h_left == h_right: return 2**h_left - 1 return 1 + self.countNodes(root.right) + self.countNodes(root.left)

222. Count Complete Tree Nodes Given a complete binary tree, count the number of nodes. Note: Definition of a complete binary tree from Wikipedia:In a complete binary tree every level, except possibly the last, is completely filled, and all nodes in the last level are as far left as possible. It can have between 1 and 2h nodes inclusive at the last level h.

input: output: test cases: Assumption: No Data Structure: No one queue Algorithm: When push, append element to q and use one variable to store top element. When pop, pop n-2 elements. record n-1 element as top element and pop element n. Time complexity: O(n) Space complexity: O(n) class MyStack(object): def __init__(self): self.q = deque() self.top_element = None def push(self, x): self.q.append(x) self.top_element = x def pop(self): size = len(self.q) for i in range(size-2): self.q.append(self.q.popleft()) self.top_element = self.q[0] self.q.append(self.q.popleft()) return self.q.popleft() def top(self): return self.top_element def empty(self): return len(self.q) == 0 return 1 + self.countNodes(root.right) + self.countNodes(root.left)

225. Implement Stack using Queues Implement the following operations of a stack using queues. push(x) -- Push element x onto stack. pop() -- Removes the element on top of the stack. top() -- Get the top element. empty() -- Return whether the stack is empty.

Time complexity: Space complexity: class Solution(object): def invertTree(self, root): if root is None: return None left_node = root.left right_node = root.right root.left = self.invertTree(right_node) root.right = self.invertTree(left_node) return root

226. Invert Binary Tree Invert a binary tree.

input: an array of linked lists output: one linked list test cases: 1->4->5, 1->3->4, 2->6 => 1->1->2->3->4->4->5->6 Assumption: No Data Structure: min heap: store the mapping of first node value and the linked list Algorithm: Min Heap Pop the top element of min heap and push the next element. Time complexity: O(nlogk) Space complexity: O(n) class Solution(object): def mergeKLists(self, lists): minheap = [] heapq.heapify(minheap) d = ListNode() curr = d for l in lists: if l: heappush(minheap, (l.val, l)) while minheap: node = heappop(minheap)[1] curr.next = node if node.next: heappush(minheap, (node.next.val, node.next)) curr = curr.next return d.next

23. Merge k Sorted Lists Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.

input: one linked lists output: one linked list test cases: 1->2->3->4 => 2->1->4->3 Assumption: not modify the values in the list's node Data Structure: No Algorithm: Iteration Time complexity: O(n) Space complexity: O(1) class Solution(object): def swapPairs(self, head): d = ListNode() d.next = head prev = d curr = head while curr and curr.next: first_node = curr second_node = curr.next prev.next = second_node first_node.next = second_node.next second_node.next = first_node prev = first_node curr = first_node.next return d.next

24. Swap Nodes in Pairs Given a linked list, swap every two adjacent nodes and return its head.

input: one array output: one integer test cases: [1, 1, 2] => 2 Assumption: modify the input array in-place with O(1) extra memory Data Structure: No Algorithm: Two Pointer 1. Keep moving P2 2. If nums[p1] != nums[p2]: assign the value and move P1 Time complexity: O(n) Space complexity: O(1) class Solution(object): def removeDuplicates(self, nums): p1, p2 = 0, 1 while (p2 < len(nums)): if nums[p2] != nums[p1]: p1 += 1 nums[p1] = nums[p2] p2 += 1 return p1+1

26. Remove Duplicates from Sorted Array Given a sorted array nums, remove the duplicates in-place such that each element appear only once and return the new length.

input: one array, one integer output: one integer test cases: [3,2,2,3], 3 => 2 Assumption: modify the input array in-place with O(1) extra memory Data Structure: No Algorithm: Two Pointer 1. Keep moving P2 2. If val != nums[p2]: assign the value and move P1 Time complexity: O(n) Space complexity: O(1) class Solution(object): def removeElement(self, nums, val): p1 = 0 for p2 in range(len(nums)): if nums[p2] != val: nums[p1] = nums[p2] p1 += 1 return p1

27. Remove Element Given an array nums and a value val, remove all instances of that value in-place and return the new length.

input: one string output: one integer test case: "abcabcbb" => 3 Assumption: No Data Structure: hashtable: record the occurrence of a character Algorithm: Sliding Window 1. expand sliding window: occurrence <= 1 2. shrink sliding window: occurrence > 1 Time complexity: O(n) Space complexity: O(min(m, n)), the size of the charset/alphabet m class Solution(object): def isValid(self, window): for k in window: if window[k] > 1: return False return True def lengthOfLongestSubstring(self, s): left, right = 0, 0 res = 0 window = {} while right < len(s): c = s[right] if c not in window: window[c] = 1 else: window[c] += 1 while not self.isValid(window): c = s[left] window[c] -= 1 left += 1 res = max(res, right-left+1) right += 1 return res

3. Longest Substring Without Repeating Characters Given a string, find the length of the longest substring without repeating characters.

input: one array, one integer output: one integer test cases: [4,5,6,7,0,1,2], 0 => 4 Assumption: no duplicate exists in the array Data Structure: No Algorithm: Binary search Time complexity: O(log n) Space complexity: O(1) class Solution(object): def search(self, nums, target): if len(nums) == 0: return -1 start = 0 end = len(nums)-1 while start + 1 < end: mid = start + (end-start)/2 if nums[mid] == target: return mid if nums[mid] >= nums[0]: if nums[start] <= target < nums[mid]: end = mid else: start = mid else: if nums[mid] < target <= nums[end]: start = mid else: end = mid if nums[start] == target: return start if nums[end] == target: return end return -1

33. Search in Rotated Sorted Array Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand. (i.e., [0,1,2,4,5,6,7] might become [4,5,6,7,0,1,2]). You are given a target value to search. If found in the array return its index, otherwise return -1.

input: one array, one integer output: one integer test cases: [5,7,7,8,8,10], 8 => [3, 4] Assumption: No Data Structure: No Algorithm: Binary search Time complexity: O(log n) Space complexity: O(1) class Solution(object): def searchRange(self, nums, target): res = [-1, -1] if nums == [] or target < nums[0] or target > nums[-1]: return res res[0] = self.binarySearchBegin(nums, target, False) res[1] = self.binarySearchEnd(nums, target, True) return res def binarySearchBegin(self, nums, target, flag): start = 0 mid = 0 end = len(nums) - 1 while start <= end: mid = start + (end - start)/2 if nums[mid] < target: start = mid+1 elif nums[mid] > target: end = mid-1 else: end = mid-1 if start < len(nums) and nums[start] == target: return start return -1 def binarySearchEnd(self, nums, target, flag): start = 0 mid = 0 end = len(nums) - 1 while start <= end: mid = start + (end - start)/2 if nums[mid] < target: start = mid+1 elif nums[mid] > target: end = mid-1 else:start = mid + 1 if end >= 0 and nums[end] == target: return end return -1

34. Find First and Last Position of Element in Sorted Array Given an array of integers nums sorted in ascending order, find the starting and ending position of a given target value. If the target is not found in the array, return [-1, -1].

input: one array, one integer output: one integer test cases: [1,3,5,6], 5 => 2 [1,3,5,6], 2 => 1 Assumption: no duplicates in the array Data Structure: No Algorithm: Binary search Time complexity: O(log n) Space complexity: O(1) class Solution(object): def searchInsert(self, nums, target): if len(nums) == 0 or target <= nums[0]: return 0 if target > nums[-1]: return len(nums) start = 0 end = len(nums)-1 while start <= end: mid = start + (end-start)/2 if target == nums[mid]: return mid if target > nums[mid]: start = mid+1 else: end = mid-1 return start

35. Search Insert Position Given a sorted array 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.

input: one array output: one integer test cases: [1,2,0] =>3 [7,8,9,11,12] => 1 Assumption: No Data Structure: No Algorithm: Cycle Sort Keep swap elements until the elements are in the correct places Time complexity: O(n) Space complexity: O(1) class Solution(object): def firstMissingPositive(self, nums): n = len(nums) i = 0 while i < n: j = nums[i] - 1 if 0 <= j < n and nums[j] != nums[i]: nums[j], nums[i] = nums[i], nums[j] else: i += 1 for i in range(len(nums)): if nums[i] != i+1: return i+1 return len(nums)+1

41. First Missing Positive Given an unsorted integer array, find the smallest missing positive integer.

input: one array output: one integer test cases: [0,1,0,2,1,0,1,3,2,1,2,1] => 6 Assumption: No Data Structure: Monotonic Increasing Stack: find the left low boundary top_element: left bond pop_element: study object push_element: right bond Algorithm: Monotonic Increasing Stack a = push_element - top_element_index - 1 b = min(right_bond - top_element) - pop_element Area = a*b Time complexity: O(n) Space complexity: O(n) class Solution(object): def trap(self, height): stack = [] res = 0 for i, h in enumerate(height): while stack and h > height[stack[-1]]: j = stack.pop() if stack: left = stack[-1] a = i - left - 1 b = min(h, height[stack[-1]]) - height[j] res += a * b stack.append(i) return res

42. Trapping Rain Water Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how much water it is able to trap after raining.

input: one array output: one list of arrays test cases: Assumption: No Data Structure: List: use a list to track the current permutations Algorithm: Backtracking End condition: len(track) == len(nums) Choice: add num Time complexity: O(N!/(N-k)!) Space complexity: O(N!) class Solution(object): def __init__(self): self.res = [] def permute(self, nums): self.backtrack(nums, []) return self.res def backtrack(self, nums, track): if len(track) == len(nums): self.res.append(track[:]) return for n in nums: if n in track: continue track.append(n) self.backtrack(nums, track) track.pop()

46. Permutations Given a collection of distinct integers, return all possible permutations.

input: one array of strings output: one list of arrays of strings test cases: ["eat", "tea", "tan", "ate", "nat", "bat"] => [ ["ate","eat","tea"], ["nat","tan"], ["bat"] ] Assumption: No Data Structure: Hashmap: store the mapping between sorted string and actual string Algorithm: Iterative Time complexity: O(n k log k) Space complexity: O(nk) class Solution(object): def groupAnagrams(self, strs): hashmap = {} for i, s in enumerate(strs): s = ''.join(sorted(s)) if s in hashmap: hashmap[s].append(i) else: hashmap[s] = [i] res = [] for key in hashmap: temp = [] for i in hashmap[key]: temp.append(strs[i]) res.append(temp) return res

49. Group Anagrams Given an array of strings, group anagrams together.

input: one string output: one string test case: "babad" => "bab" Assumption: No Data Structure: 2-d array DP[i][j]: if the substring s[i:j+1] is a palindrome Algorithm: Dynamic Programming 1. Transition function: DP[i][j] = (s[i] == s[j]) and DP[i+1][j-1] 2. Base cases: DP[i][j] = True DP[i][i+1] = (s[i] == s[i+1]) Time complexity: O(n^2) Space complexity: O(n^2) class Solution(object): def longestPalindrome(self, s): if len(set(s)) <= 1: return s max_len = 1 res = s[0] n = len(s) dp = [[True]*n for _ in range(n)] for i in range(n-1, -1, -1): for j in range(i+1, n): if (dp[i+1][j-1] == True) and (s[i] == s[j]): dp[i][j] = True if (j-i+1) > max_len: max_len = j-i+1 res = s[i:j+1] else: dp[i][j] = False return res

5. Longest Palindromic Substring Given a string s, find the longest palindromic substring in s. You may assume that the maximum length of s is 1000.

input: one integer output: one list of arrays of strings test cases: Assumption: No Data Structure: List: use a list to track the solution Algorithm: Backtracking End condition: row == len(nums) Choice: put Q in each col Time complexity: O(N!) Space complexity: O(N) class Solution(object): def __init__(self): self.res = [] def isValid(self, board, row, col): for i in range(len(board)): if board[i][col] is 'Q': return False for j in range(len(board)): if board[row][j] is 'Q': return False all_direction = [[1, 1], [1, -1], [-1, 1], [-1, -1]] for dx, dy in all_direction: i, j = row, col while 0 <= i < len(board) and 0 <= j < len(board): if board[i][j] is 'Q': return False i += dy j += dx return True def solveNQueens(self, n): board = [] for i in range(n): row = "" for j in range(n): row += "." board.append(row) self.backtrack(board, 0) return self.res def backtrack(self, board, row): if row == len(board): self.res.append(board[:]) return for col in range(len(board)): if self.isValid(board, row, col): board[row] = board[row][:col] + 'Q' + board[row][col+1:] self.backtrack(board, row+1) board[row] = board[row][:col] + '.' + board[row][col+1:]

51. N-Queens The n-queens puzzle is the problem of placing n queens on an n×n chessboard such that no two queens attack each other. Given an integer n, return all distinct solutions to the n-queens puzzle. Each solution contains a distinct board configuration of the n-queens' placement, where 'Q' and '.' both indicate a queen and an empty space respectively.

input: one array output: one integer test cases: [-2,1,-3,4,-1,2,1,-5,4] => 6 Assumption: No Data Structure: 2-d array DP[i]: the max sum of subarray of nums[:i] Algorithm: Dynamic Programming Transition Function: DP[i] = max(nums[i], DP[i-1] + nums[i]) Base cases: DP[0] = nums[0] Time complexity: O(N) Space complexity: O(1) class Solution(object): def maxSubArray(self, nums): dp = nums for i in range(1, len(nums)): dp[i] = max(nums[i], dp[i-1] + nums[i]) return max(dp)

53. Maximum Subarray Given an integer array nums, find the contiguous subarray (containing at least one number) which has the largest sum and return its sum.

input: one matrix output: one array test cases: Assumption: No Data Structure: No Algorithm: Simulation Time complexity: O(N) Space complexity: O(N) class Solution(object): def spiralOrder(self, matrix): if not matrix: return [] R, C = len(matrix), len(matrix[0]) seen = [[False] * C for _ in matrix] ans = [] dr = [0, 1, 0, -1] dc = [1, 0, -1, 0] r = c = di = 0 for _ in range(R * C): ans.append(matrix[r][c]) seen[r][c] = True cr, cc = r + dr[di], c + dc[di] if 0 <= cr < R and 0 <= cc < C and not seen[cr][cc]: r, c = cr, cc else: di = (di + 1) % 4 r, c = r + dr[di], c + dc[di] return ans

54. Spiral Matrix Given a matrix of m x n elements (m rows, n columns), return all elements of the matrix in spiral order.

input: a list of intervals output: a list of intervals test cases: [[1,3],[2,6],[8,10],[15,18]] => [[1,6],[8,10],[15,18]] Assumption: No Data Structure: No Algorithm: Sort Time complexity: O(N log N) Space complexity: O(N) class Solution(object): def merge(self, intervals): if len(intervals) < 2: return intervals intervals.sort(key=lambda x: x[0]) start = intervals[0][0] end = intervals[0][1] res = [] for i in range(1, len(intervals)): if intervals[i][0] <= end: end = max(end, intervals[i][1]) else: res.append([start, end]) start = intervals[i][0] end = intervals[i][1] res.append([start, end]) return res

56. Merge Intervals Given a collection of intervals, merge all overlapping intervals.

input: a list of intervals, an interval output: a list of intervals test cases: intervals = [[1,3],[6,9]], newInterval = [2,5] => [[1,5],[6,9]] Assumption: The intervals were initially sorted according to their start times. Data Structure: No Algorithm: Greedy Time complexity: O(N) Space complexity: O(N) class Solution(object): def insert(self, intervals, newInterval): res = [] i = 0 while i < len(intervals) and newInterval[0] > intervals[i][1]: res.append(intervals[i]) i+=1 while i < len(intervals) and newInterval[1] >= intervals[i][0]: newInterval[0] = min(intervals[i][0], newInterval[0]) newInterval[1] = max(intervals[i][1], newInterval[1]) i+=1 res.append(newInterval) while i < len(intervals): res.append(intervals[i]) i+=1 return res

57. Insert Interval Given a set of non-overlapping intervals, insert a new interval into the intervals (merge if necessary).

input: two integers output: one integer test cases: Assumption: No Data Structure: a 2-D array DP[i][j]: the all possible paths to reach (i, j) Algorithm: Dynamic Programming Transition Function: DP[i][j] = DP[i-1][j] + DP[i][j-1] Base Cases: DP[0][j] = DP[i][0] = 1 Time complexity: O(NM) Space complexity: O(NM) class Solution(object): def uniquePaths(self, m, n): dp = [[1]*n for _ in range(m)] for i in range(1, m): for j in range(1, n): dp[i][j] = dp[i-1][j] + dp[i][j-1] return dp[m-1][n-1]

62. Unique Paths A robot is located at the top-left corner of a m x n grid (marked 'Start' in the diagram below). The robot can only move either down or right at any point in time. The robot is trying to reach the bottom-right corner of the grid (marked 'Finish' in the diagram below). How many possible unique paths are there?

input: one matrix output: one integer test cases: Assumption: No Data Structure: a 2-D array DP[i][j]: the all possible paths to reach (i, j) Algorithm: Dynamic Programming Time complexity: O(NM) Space complexity: O(NM) class Solution(object): def uniquePathsWithObstacles(self, obstacleGrid): if obstacleGrid[0][0] == 1: return 0 m = len(obstacleGrid) n = len(obstacleGrid[0]) dp = [[0]*n for _ in range(m)] dp[0][0] = 1 for i in range(1, m): if obstacleGrid[i][0] != 1: dp[i][0] = dp[i-1][0] for j in range(1, n): if obstacleGrid[0][j] != 1: dp[0][j] = dp[0][j-1] for i in range(1, m): for j in range(1, n): if obstacleGrid[i][j] != 1: dp[i][j] = dp[i-1][j] + dp[i][j-1] return dp[m-1][n-1]

63. Unique Paths II A robot is located at the top-left corner of a m x n grid (marked 'Start' in the diagram below). The robot can only move either down or right at any point in time. The robot is trying to reach the bottom-right corner of the grid (marked 'Finish' in the diagram below). Now consider if some obstacles are added to the grids. How many unique paths would there be? An obstacle and empty space is marked as 1 and 0 respectively in the grid.

input: one matrix output: one integer test cases: Assumption: No Data Structure: a 2-D array DP[i][j]: the min cost to reach (i, j) Algorithm: Dynamic Programming Time complexity: O(NM) Space complexity: O(NM) class Solution(object): def minPathSum(self, grid): m = len(grid) n = len(grid[0]) dp = [[0]*n for _ in range(m)] dp[0][0] = grid[0][0] for i in range(1, m): dp[i][0] = dp[i-1][0] + grid[i][0] for j in range(1, n): dp[0][j] = dp[0][j-1] + grid[0][j] for i in range(1, m): for j in range(1, n): dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + grid[i][j] return dp[m-1][n-1]

64. Minimum Path Sum Given a m x n grid filled with non-negative numbers, find a path from top left to bottom right which minimizes the sum of all numbers along its path.

input: one integer output: one integer test cases: Assumption: No Data Structure: No Algorithm: Fibonacci Number Time complexity: O(n) Space complexity: O(1) class Solution(object): def climbStairs(self, n): if n <= 2: return n p1 = 1 p2 = 2 for _ in range(3, n+1): res = p1 + p2 p1 = p2 p2 = res return res

70. Climbing Stairs You are climbing a stair case. It takes n steps to reach to the top. Each time you can either climb 1 or 2 steps. In how many distinct ways can you climb to the top?

input: two strings output: one integer test cases: Assumption: No Data Structure: a 2-D array DP[i][j]: the min num of operations to transfer word1[0:i-1] to word2[0:j-1] Algorithm: Dynamic Programming 1. Transition Function: DP[i][j] = DP[i-1][j-1] if word1[i-1] == word2[j-1] DP[i][j] = 1+ min(DP[i-1][j-1], DP[i][j-1], DP[i-1][j]) 2. Base Cases: DP[i][0] = i, DP[0][j] = j Time complexity: O(mn) Space complexity: O(mn) class Solution(object): def minDistance(self, word1, word2): n = len(word1) m = len(word2) dp = [[0] * (m+1) for _ in range(n+1)] for i in range(n+1): dp[i][0] = i for j in range(m+1): dp[0][j] = j for i in range(1, n+1): for j in range(1, m+1): if word1[i-1] == word2[j-1]: dp[i][j] = dp[i-1][j-1] else: dp[i][j] = 1 + min(dp[i-1][j-1], dp[i][j-1], dp[i-1][j]) return dp[n][m]

72. Edit Distance Given two words word1 and word2, find the minimum number of operations required to convert word1 to word2. You have the following 3 operations permitted on a word: Insert a character Delete a character Replace a character

input: one array output: one array test cases: [2,0,2,1,1,0] => [0,0,1,1,2,2] Assumption: a 2-D array DP[i][j]: the min num of operations to transfer word1[0:i-1] to word2[0:j-1] Data Structure: No Algorithm: Three Pointers 1. 1st pointer points to the start 2. 2nd pointer points traverses the array. 3. 3rd pointer points to the end. 4. If 0 is found by 2nd pointer, swap the 2nd and 1st, increment 1st and 2nd. 5. If 1 is found by 2nd pointer, increment 2nd. 6. If 2 is found by 2nd pointer, swap the 2nd and 3rd, decrement 3rd. Time complexity: O(n) Space complexity: O(1) class Solution(object): def sortColors(self, nums): p1 = 0 p2 = len(nums)-1 i = 0 while i <= p2: if nums[i] == 0: nums[p1], nums[i] = nums[i], nums[p1] p1 += 1 i += 1 elif nums[i] == 2: nums[p2], nums[i] = nums[i], nums[p2] p2 -= 1 else: i += 1 return nums

75. Sort Colors Given an array with n objects colored red, white or blue, sort them in-place so that objects of the same color are adjacent, with the colors in the order red, white and blue. Here, we will use the integers 0, 1, and 2 to represent the color red, white, and blue respectively.

input: Two strings output: one string test cases: S = "ADOBECODEBANC", T = "ABC" => "BANC" Assumption: No Data Structure: hashtable: record the occurrence in the window hashtable: record the required occurrence Algorithm: Sliding Window 1. expand sliding window 2. shrink sliding window: window >= need Time complexity: O(|S| + |T|) Space complexity: O(|S| + |T|) class Solution(object): def isValid(self, window, need): for key in need: if window[key] < need[key]: return False return True def minWindow(self, s, t): left, right = 0, 0 need = {} window = {} min_len = float('inf') res = "" for c in t: window[c] = 0 if c in need: need[c] += 1 else: need[c] = 1 while right < len(s): c = s[right] if c in window: window[c] += 1 while self.isValid(window, need): if len(t) <= (right - left + 1) < min_len: min_len = right - left + 1 res = s[left:right+1] c = s[left] if c in window: window[c] = max(0, window[c] - 1) left += 1 right += 1 return res

76. Minimum Window Substring Given a string S and a string T, find the minimum window in S which will contain all the characters in T in complexity O(n).

input: an array output: a list of arrays test cases: [1,2,3] => [ [3], [1], [2], [1,2,3], [1,3], [2,3], [1,2], [] ] Assumption: No Data Structure: No Algorithm: Backtracking Run Backtracking for different k 1. End condition: len(curr) == k 2. Choices: add num Time complexity: O(N*2^N) Space complexity: O(N*2^N) class Solution(object): def __init__(self): self.res = [] def backtrack(self, f, curr, k, nums): if len(curr) == k: self.res.append(curr[:]) for i in range(f, len(nums)): curr.append(nums[i]) self.backtrack(i+1, curr, k, nums) curr.pop() def subsets(self, nums): for k in range(len(nums)+1): self.backtrack(0, [], k, nums) return self.res

78. Subsets Given a set of distinct integers, nums, return all possible subsets (the power set).

input: a matrix, a string output: True or False test cases: board = [ ['A','B','C','E'], ['S','F','C','S'], ['A','D','E','E'] ], "ABCCED" => True Assumption: No Data Structure: No Algorithm: Backtracking Run Backtracking for every start 1. End condition: len(word) == 0: return True word[0] not matched or out of boundary: return False 2. Choices: upper, down, left, right Time complexity: O(N*4^N) Space complexity: O(N*4^N) class Solution(object): def exist(self, board, word): m = len(board) n = len(board[0]) start = [] for i in range(m): for j in range(n): if self.backtrack(board, word, i, j): return True return False def backtrack(self, board, word, i, j): if len(word) == 0: return True if i < 0 or i > (len(board) - 1) or j < 0 or j > (len(board[0]) - 1) or word[0] != board[i][j]: return False board[i][j] = '' direction = [[1, 0], [-1, 0], [0, -1], [0, 1]] for d in direction: res = self.backtrack(board, word[1:], i+d[0], j+d[1]) if res: break board[i][j] = word[0] return res

79. Word Search Given a 2D board and a word, find if the word exists in the grid. The word can be constructed from letters of sequentially adjacent cell, where "adjacent" cells are those horizontally or vertically neighboring. The same letter cell may not be used more than once.

input: an array output: one integer test cases: board = [ ['A','B','C','E'], ['S','F','C','S'], ['A','D','E','E'] ], "ABCCED" => True Assumption: No Data Structure: No Algorithm: Overwriting unwanted duplicates 1st pointer: keep track of the next location in the array where we can overwrite an element 2nd pointer: traverse the array Time complexity: O(N) Space complexity: O(1) class Solution(object): def removeDuplicates(self, nums): if len(nums) <= 2: return len(nums) p1 = 1 count = 1 for p2 in range(1, len(nums)): if nums[p2] == nums[p2-1]: count += 1 else: count = 1 if count <= 2: nums[p1] = nums[p2] p1 += 1 return p1

80. Remove Duplicates from Sorted Array II Given a sorted array nums, remove the duplicates in-place such that duplicates appeared at most twice and return the new length.

input: an array, an integer output: one integer test cases: nums = [2,5,6,0,0,1,2], target = 0 => True Assumption: No Data Structure: No Algorithm: Binary Search Time complexity: O(log N) Space complexity: O(1) class Solution(object): def search(self, nums, target): if len(nums) == 0: return False start = 0 end = len(nums)-1 while start + 1 < end: mid = start + (end-start)/2 if nums[mid] == target: return True if nums[mid] > nums[start]: if nums[start] <= target < nums[mid]: end = mid else: start = mid elif nums[mid] < nums[start]: if nums[mid] < target <= nums[end]: start = mid else: end = mid else: start += 1 if nums[start] == target or nums[end] == target: return True return False

81. Search in Rotated Sorted Array II Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand. (i.e., [0,0,1,2,2,5,6] might become [2,5,6,0,0,1,2]). You are given a target value to search. If found in the array return true, otherwise return false.

input: a linked list output: a linked list test cases: 1->2->3->3->4->4->5 => 1->2->5 Assumption: No Data Structure: No Algorithm: Traverse Use temp pointer to skip equal valued nodes Time complexity: O(N) Space complexity: O(1) class Solution(object): def deleteDuplicates(self, head): d = ListNode(0) d.next = head prev = d curr = head while curr: val = curr.val temp = curr.next while temp and temp.val == val: temp = temp.next if temp == curr.next: prev = curr else: prev.next = temp curr = temp return d.next

82. Remove Duplicates from Sorted List II Given a sorted linked list, delete all nodes that have duplicate numbers, leaving only distinct numbers from the original list. Return the linked list sorted as well.

input: a linked list output: a linked list test cases: 1->1->2 => 1->2 Assumption: No Data Structure: No Algorithm: Traverse Use temp pointer to skip equal valued nodes Time complexity: O(N) Space complexity: O(1) class Solution(object): def deleteDuplicates(self, head): curr = head while curr: temp = curr.next while temp and temp.val == curr.val: temp = temp.next curr.next = temp curr = curr.next return head

83. Remove Duplicates from Sorted List Given a sorted linked list, delete all duplicates such that each element appear only once

input: one array output: one integer test cases: [2,1,5,6,2,3] => 10 Assumption: No Data Structure: Monotonic Decreasing Stack: find the left low boundary top_element: left bond pop_element: study object push_element: right bond Algorithm: Monotonic Increasing Stack a = push_element - top_element_index - 1 b = pop_element Area = a*b Time complexity: O(n) Space complexity: O(n) class Solution(object): def largestRectangleArea(self, heights): stack = [] res = 0 for i, h in enumerate(heights + [0]): while stack and h < heights[stack[-1]]: j = stack.pop() if stack: left = stack[-1] else: left = -1 a = i - left - 1 b = heights[j] res = max(res, a*b) stack.append(i) return res

84. Largest Rectangle in Histogram Given n non-negative integers representing the histogram's bar height where the width of each bar is 1, find the area of largest rectangle in the histogram.

input: one matrix output: one integer test cases: [ ["1","0","1","0","0"], ["1","0","1","1","1"], ["1","1","1","1","1"], ["1","0","0","1","0"] ] => 6 Assumption: No Data Structure: a 2-D array DP[i][j]: max consecutive 1 ended with matrix[i][j] in row i Algorithm: Dynamic Programming Transition Function: DP[i][j] = DP[i][j-1] + 1 if matrix[i][j] == '1' Base Case: DP[i][0] = 1 if matrix[i][j] == '1' Time complexity: O(MN) Space complexity: O(MN) class Solution(object): def maximalRectangle(self, matrix): if matrix == []: return 0 m, n = len(matrix), len(matrix[0]) dp = [[0]*n for _ in range(m)] res = 0 for i in range(m): for j in range(n): if matrix[i][j] == '0': continue dp[i][j] = dp[i][j-1] + 1 if j else 1 width = dp[i][j] for k in range(i, -1, -1): width = min(width, dp[k][j]) res = max(res, width*(i-k+1)) return res

85. Maximal Rectangle Given a 2D binary matrix filled with 0's and 1's, find the largest rectangle containing only 1's and return its area.

Algorithm: Iterative Time complexity: O(N) Space complexity: O(1) class Solution(object): def inorderTraversal(self, root): res = [] stack = [] curr = root while stack or curr: if curr: stack.append(curr) curr = curr.left continue curr = stack.pop() res.append(curr.val) curr = curr.right return res

94. Binary Tree Inorder Traversal Given a binary tree, return the inorder traversal of its nodes' values.

input: three strings output: True or False test cases: s1 = "aabcc", s2 = "dbbca", s3 = "aadbbcbcac" => True Assumption: No Data Structure: a 2-D array DP[i][j]: if s1[:i] and s2[:j] can form s3[:i+j] Algorithm: Dynamic Programming Transition Function: DP[i][j] = (DP[i-1][j] and s1[i-1] == s3[i+j-1]) or (DP[i][j-1] and s2[j-1] == s3[i+j-1]) Base Cases: DP[i][0] = DP[i-1][0] and (s1[i-1] == s3[i-1]) DP[0][j] = DP[0][j-1] and (s2[j-1] == s3[j-1]) Time complexity: O(MN) Space complexity: O(MN) class Solution(object): def isInterleave(self, s1, s2, s3): if (len(s1) + len(s2)) != len(s3): return False m = len(s1) + 1 n = len(s2) + 1 dp = [[False] * n for _ in range(m)] dp[0][0] = True for i in range(1, m): dp[i][0] = dp[i-1][0] and (s1[i-1] == s3[i-1]) for j in range(1, n): dp[0][j] = dp[0][j-1] and (s2[j-1] == s3[j-1]) for i in range(1, m): for j in range(1, n): dp[i][j] = (dp[i-1][j] and s1[i-1] == s3[i+j-1]) or (dp[i][j-1] and s2[j-1] == s3[i+j-1]) return dp[m-1][n-1]

97. Interleaving String Given s1, s2, s3, find whether s3 is formed by the interleaving of s1 and s2.

input: Tree node output: True or False test cases: Assumption: No Data Structure: No Algorithm: Recursion use min_node and max_node to record upper nodes Time complexity: O(N) Space complexity: O(N) class Solution(object): def isValidBST(self, root): return self.helper(root, None, None) def helper(self, root, min_node, max_node): if root is None: return True if min_node is not None and root.val <= min_node.val: return False if max_node is not None and root.val >= max_node.val: return False return self.helper(root.left, min_node, root) and \ self.helper(root.right, root, max_node)

98. Validate Binary Search Tree Given a binary tree, determine if it is a valid binary search tree (BST). Assume a BST is defined as follows: The left subtree of a node contains only nodes with keys less than the node's key. The right subtree of a node contains only nodes with keys greater than the node's key. Both the left and right subtrees must also be binary search trees.

input: Tree node output: Tree node test cases: Assumption: No Data Structure: No Algorithm: In-order Traverse BST in-order traverse => sorted array use one pointer PREV to track the previous node use P1 and P2 to track the swapped nodes Time complexity: O(N) Space complexity: O(N) class Solution(object): def traverse(self, root): if not root: return self.traverse(root.left) if self.prev and self.prev.val > root.val: if not self.p1: self.p1 = self.prev self.p2 = root self.prev = root self.traverse(root.right) def recoverTree(self, root): self.p1, self.p2, self.prev = None, None, None self.traverse(root) self.p1.val, self.p2.val = self.p2.val, self.p1.val return root

99. Recover Binary Search Tree Two elements of a binary search tree (BST) are swapped by mistake. Recover the tree without changing its structure.


Conjuntos de estudio relacionados

The President's Cabinet and Their Roles

View Set

Introduction to Macroeconomics Quiz

View Set

BCH480 All quizzes/Test Questions

View Set