LeetCode approaches

Ace your homework & exams now with Quizwiz!

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

Insight/Solution: classic DP problem, essentially fibonacci sequence since we can take a step of size 1 or 2, we can produce this recursive expression dp[i] = 1 if i = 0 or i = 1 dp[i] = dp[i - 1] + dp[i - 2] if i > 1

200. Number of Islands Given an m x n 2d grid map of '1's (land) and '0's (water), return 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. Constraints: m == grid.length n == grid[i].length 1 <= m, n <= 300 grid[i][j] is '0' or '1'.

Insight/Solution: DFS, we traverse through the grid, and if we hit grid[i][j] = '1', we increment our count by 1 and perform a DFS to change all the land connected to this spot with '*' (marking it as seen), that way, we can keep track of the number of islands we have

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.

Insight/Solution: Either use one stack with tuples, or two stacks Tuples: (x, min_value of stack) Two Stacks: look into it and update this flashcard

417. Pacific Atlantic Water Flow Given an m x n matrix of non-negative integers representing the height of each unit cell in a continent, the "Pacific ocean" touches the left and top edges of the matrix and the "Atlantic ocean" touches the right and bottom edges. Water can only flow in four directions (up, down, left, or right) from a cell to another one with height equal or lower. Find the list of grid coordinates where water can flow to both the Pacific and Atlantic ocean. Note: The order of returned grid coordinates does not matter. Both m and n are less than 150.

Insight/Solution: BFS or DFS, for me, more intuitive to think of it as a DFS problem use two visited sets, one for the pacific ocean and the other for atlantic ocean, from each border of either ocean, conduct DFS and accordingly determine which coordinates are reachable for each ocean pick the intersections of the visited sets as our solution

286. Walls and Gates You are given a m x n 2D grid initialized with these three possible values. -1 - A wall or an obstacle. 0 - A gate. INF - Infinity means an empty room. We use the value 231 - 1 = 2147483647 to represent INF as you may assume that the distance to a gate is less than 2147483647. Fill each empty room with the distance to its nearest gate. If it is impossible to reach a gate, it should be filled with INF.

Insight/Solution: BFS problem, we put all the locations of our gates into the queue, and conduct BFS, if the new room we are on has a larger value than our current room, set the new room's value to the current room's + 1 and add the new location into our queue

310. Minimum Height Trees A tree is an undirected graph in which any two vertices are connected by exactly one path. In other words, any connected graph without simple cycles is a tree. Given a tree of n nodes labelled from 0 to n - 1, and an array of n - 1 edges where edges[i] = [ai, bi] indicates that there is an undirected edge between the two nodes ai and bi in the tree, you can choose any node of the tree as the root. When you select a node x as the root, the result tree has height h. Among all possible rooted trees, those with minimum height (i.e. min(h)) are called minimum height trees (MHTs). Return a list of all MHTs' root labels. You can return the answer in any order. The height of a rooted tree is the number of edges on the longest downward path between the root and a leaf. Constraints: 1 <= n <= 2 * 104 edges.length == n - 1 0 <= ai, bi < n ai != bi All the pairs (ai, bi) are distinct. The given input is guaranteed to be a tree and there will be no repeated edges.

Insight/Solution: BFS/Topological Sort, for this explanation, we will focus on BFS There are a few key points to note before solving the problem, since we are working with a tree, we know the graph is acyclic and fully connected, the height of a tree is the maximum length from a root to a leaf, also somewhat obscure, there is only one path to get from one node to another node now consider a piece of tissue, if you hold it on the corner, the height of your tissue is at its largest, but if we want the minimum height, we actually should hold our tissue at its centroid, and this analogy translates directly to this problem, we need to find the centroid nodes with the knowledge we got beforehand, we know that the can be at most 2 centroid nodes (use proof of contradiction for 3 centroid nodes), now the problem is a matter of finding centroid nodes of up to 2 use BFS in the manner that we remove the leaves of our graph, until we are left with 2 leaves (which will be the centroid nodes), to do this, initialize an adjacency list, hold leaves in a queue, then iterate through the leaves queue until it reaches <= 2 nodes, it is helpful to also have a new_leaves queue to keep track of both new leaves to store and the old leaves we are removing in our current iteration

37. Sudoku Solver Write a program to solve a Sudoku puzzle by filling the empty cells. A sudoku solution must satisfy all of the following rules: Each of the digits 1-9 must occur exactly once in each row. Each of the digits 1-9 must occur exactly once in each column. Each of the digits 1-9 must occur exactly once in each of the 9 3x3 sub-boxes of the grid. The '.' character indicates empty cells. Constraints: board.length == 9 board[i].length == 9 board[i][j] is a digit or '.'. It is guaranteed that the input board has only one solution.

Insight/Solution: Backtracking + Hash table, the idea is pretty simple actually, the coding is pretty intensive all we really need to maintain is that we make a guess for an empty cell, then determine whether the row, column, or sub-grid is validated, if it can be valid, we recursively call the function to solve again, and whenever we finally can return True, it means we have successfully solved the board if it returns False though, that means our board is unsolvable, so we have to backtrack and make a new guess for which the guess we just had was invalid, we keep backtracking as we move along and will eventually reach a solution for our board the hash tables are used so that we optimize our look-up for row, column, and sub-grid validations to constant time, other data structures can be used such as a heap

51. N-Queens The n-queens puzzle is the problem of placing n queens on an n x 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. Constraints: 1 <= n <= 9

Insight/Solution: Backtracking, honestly a very standard backtracking problem also similar to letter combinations of a phone number, etc The additional "fluff" that we have to account for is validating a queen, and this depends on our implementation, for simplicity, assume that we fill in a queen every row the idea of our backtracking implementation is to assume that our previously placed queens are valid, so we can save time by only considering if the queen we just placed is valid, since we go row by row, we can already dismiss checking if there is another queen in the same row, since that will never happen if our implementation is correct instead, we should consider the up-down case and diagonal cases, for up-down case, we just simply check if a queen is in the same column as our newly placed queen, as for diagonals, best if you draw it out, but the solution is abs(row - i) == abs(col - j), where row and col represents the newly placed queen's location

77. Combinations Given two integers n and k, return all possible combinations of k numbers out of 1 ... n. You may return the answer in any order. Constraints: 1 <= n <= 20 1 <= k <= n

Insight/Solution: Backtracking, idea is similar to permutations, letter combinations of a phone number, all the classic backtracking problems

131. Palindrome Partitioning Given a string s, partition s such that every substring of the partition is a palindrome. Return all possible palindrome partitioning of s. A palindrome string is a string that reads the same backward as forward.

Insight/Solution: Backtracking, really similar pattern to letter combinations of a phone number, permutations, and subsets

39. Combination Sum Given an array of distinct integers candidates and a target integer target, return a list of all unique combinations of candidates where the chosen numbers sum to target. You may return the combinations in any order. The same number may be chosen from candidates an unlimited number of times. Two combinations are unique if the frequency of at least one of the chosen numbers is different. It is guaranteed that the number of unique combinations that sum up to target is less than 150 combinations for the given input. Constraints: 1 <= candidates.length <= 30 1 <= candidates[i] <= 200 All elements of candidates are distinct. 1 <= target <= 500

Insight/Solution: Backtracking, similar to the classic problems Note: a simple optimization is instead of checking if target < 0, check in the for loop if candidates[i] > target, then continue instead, that way, we never have to call backtrack again if our target went negative

784. Letter Case Permutation Given a string S, we can transform every letter individually to be lowercase or uppercase to create another string. Return a list of all possible strings we could create. You can return the output in any order. Constraints: S will be a string with length between 1 and 12. S will consist only of letters or digits.

Insight/Solution: Backtracking, similar to the other classic backtracking problems

33. Search in Rotated Sorted Array You are given an integer array nums sorted in ascending order, and an integer target. Suppose that nums 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]). If target is found in the array return its index, otherwise, return -1. Constraints: 1 <= nums.length <= 5000 -10^4 <= nums[i] <= 10^4 All values of nums are unique. nums is guranteed to be rotated at some pivot. -10^4 <= target <= 10^4

Insight/Solution: Binary Search, wow this one was hard it is essentially binary search with extra cases, we have to handle for cases when we perform a standard binary search and also modified searches, the modified searches depend on the way the array has been pivoted the best way to approach the problem is simply considering how a normal binary search would handle such portions of a rotated sorted array, the easiest way to think about it is to consider the values of nums[left] or nums[right] for instance, if we search for 6 in [4,5,6,7,0,1,2], we see that nums[m] = 7, and since it is greater than target, we may have to consider a standard binary search (left portion), but to verify, we have to check if it could be in the right portion which is simply checking if nums[l] <= nums[m] and nums[l] > target, that is in fact, the only way we could have the target be in the right portion if nums[m] > target follow the same logic for the other case when nums[m] < target, and thats it

153. Find Minimum in Rotated Sorted Array Suppose an array of length n sorted in ascending order is rotated between 1 and n times. For example, the array nums = [0,1,2,4,5,6,7] might become: [4,5,6,7,0,1,2] if it was rotated 4 times. [0,1,2,4,5,6,7] if it was rotated 7 times. Notice that rotating an array [a[0], a[1], a[2], ..., a[n-1]] 1 time results in the array [a[n-1], a[0], a[1], a[2], ..., a[n-2]]. Given the sorted rotated array nums, return the minimum element of this array. Constraints: n == nums.length 1 <= n <= 5000 -5000 <= nums[i] <= 5000 All the integers of nums are unique. nums is sorted and rotated between 1 and n times.

Insight/Solution: Binary search, first consider what binary search does: it takes the middle value and compares it with the key to determine which portion to consider next, for this special case, we know that our key is simply the smaller number of the mid, once we reach both our left and right pointers at an intersection, we have reached the smallest number of the array (loop invariant) a simple way to use this invariant is to consider the mid and right values if nums[m] > nums[r], then the minimum must be in the right portion, so we set l = m + 1 otherwise, then the minimum must be in the left portion, but it could also be the middle itself, so we set r = m we have to set l = m + 1 since we know for a fact that if nums[m] is greater than even 1 other value, it cannot be the minimum, but in the case where we set r = m, we cannot rule out that nums[m] is not the minimum

494. Target Sum You are given a list of non-negative integers, a1, a2, ..., an, and a target, S. Now you have 2 symbols + and -. For each integer, you should choose one from + and - as its new symbol. Find out how many ways to assign symbols to make sum of integers equal to target S. Constraints: The length of the given array is positive and will not exceed 20. The sum of elements in the given array will not exceed 1000. Your output answer is guaranteed to be fitted in a 32-bit integer.

Insight/Solution: DFS or DP problem, do yourself a favor and implement it using memoization instead of tabulation pretty easy to consider it as a DFS problem, but it will TLE O(2^n) instead, consider the problem like a DP knapsack 0/1 problem where we add up the number of ways every time, the memoization is super easy to add afterwards I repeat, use memoization. This problem killed my interest for solving DP problems using bottom-up... unless its like coin change or something

191. Number of 1 Bits Write a function that takes an unsigned integer and returns the number of '1' bits it has (also known as the Hamming weight). Note: Note that in some languages such as Java, there is no unsigned integer type. In this case, the input will be given as a signed integer type. It should not affect your implementation, as the integer's internal binary representation is the same, whether it is signed or unsigned. In Java, the compiler represents the signed integers using 2's complement notation. Therefore, in Example 3 above, the input represents the signed integer. -3. Follow up: If this function is called many times, how would you optimize it? Constraints: The input must be a binary string of length 32

Insight/Solution: Bit manipulation, here we want to use several parts of bit manipulation: &, <<, and >> operators since the binary string has a length of 32, we can simply iterate 32 times and check if the bit we are on is a 1 or 0, use a mask to move and check the next bit, moving from right to left (use << operator) Follow-up: the & will compare the least significant bits of the two numbers, since Hamming weight requires the number of 1 bits, we know that 1 & 1 will yield 1, so we can simply compare the least significant bit of n and 1 to calculate how many 1 bits we have, afterwards, we have to move our n so that we move onto the next bit, which we can do with >> do this until n reaches 0 Note: there is another way, it is a bit manipulation trick where we continuously increment the number of bits and do n &= (n - 1) instead, this flips all the 1s to 0s, so once we reach n = 0, we have our Hamming weight

206. Reverse Linked List Reverse a singly linked list.

Insight/Solution: Can solve either iteratively or recursively Iteratively: initialize a curr pointer and prev pointer, iterate while curr is not null, continuously move curr.next to prev and prev to curr (will need a third pointer as well) recursively: idea is to work backwards once you reach the end of the linked list, remember to check for edge cases (when linked list size = 0, 1, 2)

17. Letter Combinations of a Phone Number Given a string containing digits from 2-9 inclusive, return all possible letter combinations that the number could represent. Return the answer in any order. A mapping of digit to letters (just like on the telephone buttons) is given below. Note that 1 does not map to any letters.

Insight/Solution: Classic DFS/Backtracking problem, store all possible phone combinations in a hash table and run a backtracking algorithm to create all possible combinations the implementation I have has 5 parameters: backtrack(digits, combinations, letter_map, path, index)

329. Longest Increasing Path in a Matrix Given an integer matrix, find the length of the longest increasing path. From each cell, you can either move to four directions: left, right, up or down. You may NOT move diagonally or move outside of the boundary (i.e. wrap-around is not allowed).

Insight/Solution: DFS + Memoization Brute Force approach is simply conduct a DFS and find the longest path, but that would take O(4^(mn)), what we can do though is keep track of the longest path for each cell (memoize), and that would drastically optimize the runtime to O(mn)

886. Possible Bipartition Given a set of N people (numbered 1, 2, ..., N), we would like to split everyone into two groups of any size. Each person may dislike some other people, and they should not go into the same group. Formally, if dislikes[i] = [a, b], it means it is not allowed to put the people numbered a and b into the same group. Return true if and only if it is possible to split everyone into two groups in this way.

Insight/Solution: DFS + coloring, the graph we are trying to confirm is a bipartite graph simply DFS each vertex in the graph, but instead of using our visited label as ether 0 or 1, we label each vertex with a 0 for unvisited, 1 for group A, and -1 for group B, whenever adjacent vertices are in the same group, we cannot have a bipartite graph another case to consider is if we are still exploring our depth, then you should recursively call DFS but with the other group instead (simply multiply group by -1), if all else passes without any "collisions", we confirm that the graph is not bipartite once we traverse through all the connected components, we can determine that our graph is bipartite

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

Insight/Solution: DFS on a tree Base case: An empty tree is essentially null, which would have a depth of 0. Outside of the base case, we would already have at least a depth of 1. Therefore, we can recursively solve the depth as: 1 + max(depth of left, depth of right)

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. Note: A leaf is a node with no children.

Insight/Solution: DFS on a tree, similar to Maximum Depth of Binary Tree except we have extra conditions to check we have to check if a node has one child, that has to be dealt differently, for a clear idea, consider the degenerated linked list BT

1020. Number of Enclaves Given a 2D array A, each cell is 0 (representing sea) or 1 (representing land) A move consists of walking from one land square 4-directionally to another land square, or off the boundary of the grid. Return the number of land squares in the grid for which we cannot walk off the boundary of the grid in any number of moves. Note: 1 <= A.length <= 500 1 <= A[i].length <= 500 0 <= A[i][j] <= 1 All rows have the same size.

Insight/Solution: DFS on the edges of the grid, then count up the rest of the graph where the cell = 1 edge is either when i or j = 0 or the length of grid or length of grid[0]

130. Surrounded Regions Given a 2D board containing 'X' and 'O' (the letter O), capture all regions surrounded by 'X'. A region is captured by flipping all 'O's into 'X's in that surrounded region. Explanation: Surrounded regions shouldn't be on the border, which means that any 'O' on the border of the board are not flipped to 'X'. Any 'O' that is not on the border and it is not connected to an 'O' on the border will be flipped to 'X'. Two cells are connected if they are adjacent cells connected horizontally or vertically.

Insight/Solution: DFS or BFS and coloring, the idea is to understand when will there not be a flip, turns out that if an 'O' starts at a border, it will be able to escape conduct DFS or BFS at those spots and color them as 'E' (for escaped), afterwards, iterate through the entire board, and if board[i][j] == 'E', flip it to 'O', otherwise if it is 'O', flip it to 'X'

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. class Node { public int val; public List<Node> neighbors; } Test case format: For simplicity sake, each node's value is the same as the node's index (1-indexed). For example, the first node with val = 1, the second node with val = 2, and so on. The graph is represented in the test case using an adjacency list. Adjacency list is a collection of unordered lists used to represent a finite graph. Each list describes the set of neighbors of a node in the graph. The given node will always be the first node with val = 1. You must return the copy of the given node as a reference to the cloned graph. Constraints: 1 <= Node.val <= 100 Node.val is unique for each node. Number of Nodes will not exceed 100. There is no repeated edges and no self-loops in the graph. The Graph is connected and all nodes can be visited starting from the given node.

Insight/Solution: DFS/BFS + Hash Table, use the hash table to store the deep copies of each node, use DFS/BFS to traverse through the original node to make these copies

547. Friend Circles There are N students in a class. Some of them are friends, while some are not. Their friendship is transitive in nature. For example, if A is a direct friend of B, and B is a direct friend of C, then A is an indirect friend of C. And we defined a friend circle is a group of students who are direct or indirect friends. Given a N*N matrix M representing the friend relationship between students in the class. If M[i][j] = 1, then the ith and jth students are direct friends with each other, otherwise not. And you have to output the total number of friend circles among all the students.

Insight/Solution: DFS/BFS, number of components in an undirected graph for, this time, an adjacency matrix, very similar idea as #323 on LeetCode iterate through each vertex in the graph, and conduct a DFS if we have not seen the vertex yet, keep a counter for friend circles Note: I struggled with this problem a lot due to a very stupid error, "for j in M[i]" and "for j in range(len(M[i]))" are NOT interchangeable, the former will give us only the actual cell values, so we would only visit vertices 0 and 1 if we had used the former

323. Number of Connected Components in an Undirected Graph Given n nodes labeled from 0 to n - 1 and a list of undirected edges (each edge is a pair of nodes), write a function to find the number of connected components in an undirected graph. Note: You can assume that no duplicate edges will appear in edges. Since all edges are undirected, [0, 1] is the same as [1, 0] and thus will not appear together in edges.

Insight/Solution: DFS/BFS, problem is essentially number of islands but using adjacency lists, since we are given only the edges, we have to build our adjacency list (use a hash table of lists), don't forget that it is undirected, so we have to add (v, u) in addition to (u, v) Keep track of our visited nodes in a boolean array and perform DFS, in our main loop, keep track of how many times we perform DFS, which will be the answer for the number of connected components in our graph

46. Permutations Given an array nums of distinct integers, return all the possible permutations. You can return the answer in any order. Constraints: 1 <= nums.length <= 6 -10 <= nums[i] <= 10 All the integers of nums are unique.

Insight/Solution: DFS/Backtracking problem, for every number in nums, we branch out to continue forming a permutation without including the number we just added we can use either a set to keep track of which element we've already used or pass in our nums without the element we just added: nums[:i] + nums[i + 1:] if we just added nums[i] to our path

22. Generate Parentheses Given n pairs of parentheses, write a function to generate all combinations of well-formed parentheses.

Insight/Solution: DFS/Backtracking problem, we know that our combination must have a length of 2 * n since every pair has 2 characters for the opening and closing parentheses We have to make a choice whether to add '(' or ')' to our path, always start with '(' and keep count that we can only have n number of each parenthesis, helpful to use a left count and right count for the open and closed parentheses

78. Subsets Given an integer array nums, return all possible subsets (the power set). The solution set must not contain duplicate subsets. Constraints: 1 <= nums.length <= 10 -10 <= nums[i] <= 10

Insight/Solution: DFS/Backtracking, we essentially iterate through nums, update our path, and indicate where we should start with respect to the location we are currently on (start = i + 1, when we are at position i)

1414. Find the Minimum Number of Fibonacci Numbers Whose Sum Is K Given an integer k, return the minimum number of Fibonacci numbers whose sum is equal to k. The same Fibonacci number can be used multiple times. The Fibonacci numbers are defined as: F1 = 1 F2 = 1 Fn = Fn-1 + Fn-2 for n > 2. It is guaranteed that for the given constraints we can always find such Fibonacci numbers that sum up to k. Constraints: 1 <= k <= 10^9

Insight/Solution: DP + greedy, first compute the fibonacci sequence using a DP table and stop right before the next fibonacci number becomes greater than k Now iterate, in reverse, until k reaches 0, at each iteration, we first check if k - dp[i] we are on yields a number >= 0, and if it does, we subtract dp[i] from k and keep iterating the greedy choice is picking the maximum fibonacci number that we can subtract from, recognize that if we subtract the largest value, we can effectively minimize the number of fibonacci numbers to use for our sum complexity is O(lgk)

5. Longest Palindromic Substring Given a string s, return the longest palindromic substring in s. Constraints: 1 <= s.length <= 1000 s consist of only digits and English letters (lower-case and/or upper-case),

Insight/Solution: DP problem, build an N x N matrix where N = s.length, there are several cases to consider: dp[i][j] = { T, if i == j T, if i == j - 1 and s[i] == s[j] T, if dp[i + 1][j - 1] and s[i] == s[j] F, otherwise essentially, our 2D matrix will start with a diagonal of T, and we don't consider the left bottom portion of the matrix (due to symmetry), consider the columns as pointers to the end of a substring and the rows as the beginning pointers, so we should traverse in column major order, keep track of a substring when we satisfy a T condition of our recursive expression

448. Find All Numbers Disappeared in an Array Given an array of integers where 1 ≤ a[i] ≤ n (n = size of array), some elements appear twice and others appear once. Find all the elements of [1, n] inclusive that do not appear in this array. Could you do it without extra space and in O(n) runtime? You may assume the returned list does not count as extra space.

Insight/Solution: Key here is to use every single information in this question. Use the numbers in our array as indices, and multiply the value in that index by -1 (unless it was already changed to negative, keep it as negative). Iterate once more from 0 to n - 1, and if nums[i] > 0, we know that i + 1 was a number that disappeared.

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 space is marked as 1 and 0 respectively in the grid. Constraints: m == obstacleGrid.length n == obstacleGrid[i].length 1 <= m, n <= 100 obstacleGrid[i][j] is 0 or 1.

Insight/Solution: DP problem, continuation of 62. Unique Paths dp[0][0] = { 0, if s[0][0] == 1 1, if s[0][0] == 0 dp[i][0] = { 0, if s[i][0] == 1 or dp[i - 1][0] == 0 1, otherwise ^ same with dp[0][j] dp[i][j] = { 0, if s[i][j] == 0 dp[i - 1][j] + dp[i][j - 1], otherwise if there is an obstacle in the way from our starting row or column, we cannot continue into those paths since we can only go right or down, which is why we have the conditions dp[i][0] and dp[0][j]

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. You may assume that you have an infinite number of each kind of coin.

Insight/Solution: DP problem, here is the recurrence relation: 0, if amount = 0 inf or amount + 1, if amount < 0 min of 1 <= k <= K (1 + coinChange(amount - coin)), otherwise; coin is one of the denominations in coin Essentially, we break down the number of coins we need with the type of coins we have, so if we have to make change for 6 with coins [1, 2, 5], we can determine that by 1 + number of ways to get 6 - 1, 6 - 2, and 6 - 5 Edge cases: if we can't get a certain amount, if our amount is 0

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.

Insight/Solution: DP problem, here is the recurrence relation: 1, if amount = 0 dp[i] + dp[i - coin], if coin >= i where we also initialize dp[i] = 0 the idea is to calculate the number of ways we get all amounts from 1 to amount each coin at a time, similarly with coin change, we can store our values in the manner [i - coin], since the number of ways we find a certain value depends what coin we have as well, we can add each time since for all the number of ways we can get dp[i - coin], we just have to throw in the coin value, so we keep building up to the amount of ways

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? Constraints: 1 <= m, n <= 100 It's guaranteed that the answer will be less than or equal to 2 * 109.

Insight/Solution: DP problem, here is the recursive expression: 1, if m == 1 or n == 1 f(m - 1, n) + f(m, n - 1), otherwise essentially there can only be one path if m is 1 or n is 1, since that means we can only go in that one direction

300. Longest Increasing Subsequence Given an integer array nums, return the length of the longest strictly increasing subsequence. A subsequence is a sequence that can be derived from an array by deleting some or no elements without changing the order of the remaining elements. For example, [3,6,2,7] is a subsequence of the array [0,3,1,6,2,2,7]. Follow up: Could you come up with the O(n2) solution? Could you improve it to O(n log(n)) time complexity?

Insight/Solution: DP problem, our subproblem is to find the longest subsequence without the value are currently on, in other words: dp[i] = max(dp[j])+1, ∀0≤j<i and num[i] > num[j] LIS_length​ = max(dp[i]), ∀0≤i<n Follow-up: the idea is that we can build another array called tails which holds the following invariant: (1) if x is larger than all tails, append it, increase the size by 1 (2) if tails[i-1] < x <= tails[i], update tails[i] also partially part of patience sort, we use binary search to find elements efficiently, note that since this algorithm is part of patience sort, we will only have the length of our subsequence correct, not the actual ordering of the subsequence (unless you use parent arrays and such modifications)

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. Constraints: 1 <= text1.length <= 1000 1 <= text2.length <= 1000 The input strings consist of lowercase English characters only.

Insight/Solution: DP problem, personally think it is easiest to explain using a recursion tree here is the recursive expression: f(text1, text2) = { 0, if text1 == '' or text2 == '' 1 + f(text1[1:], text2[1:]), if text1[0] == text2[0] max(f(text1[1:], text2), f(text1, text2[1:])), otherwise the idea is that we do not have a subsequence if one of the strings is empty if the first character of both strings match, then we tally up that character and continue solving the subsequence without the first characters otherwise, we could have a subsequence either when one of the strings is a subsequence, and since we want the longest common subsequence, we should take the max of both sides

452. Minimum Number of Arrows to Burst Balloons There are some 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. The start is always smaller than the end. An arrow can be shot up exactly vertically from different points along the x-axis. A balloon with xstart and xend bursts by an arrow shot at x if xstart ≤ x ≤ xend. There is no limit to the number of arrows that can be shot. An arrow once shot keeps traveling up infinitely. Given an array points where points[i] = [xstart, xend], return the minimum number of arrows that must be shot to burst all balloons. Constraints: 0 <= points.length <= 104 points[i].length == 2 -231 <= xstart < xend <= 231 - 1

Insight/Solution: Greedy algorithm, also very similar to the activity selection problem sort the points in ascending order with respect to the x_end, then note that we'll need at least 1 arrow if there is at least 1 balloon, so initialize our arrows = 1 and last_point = sorted_points[0][1], then check if our last_point < sorted_points[i][0] and if it is, we need another arrow (since that means the current arrow we had would not shoot through the balloon at i) you can use a comparator to sort the points, but you can also use a lambda function in Python lambda x: x[1] you can also sort by x[0], but that means you'll have to modify the algorithm going in reverse order

10. Regular Expression Matching Given an input string (s) and a pattern (p), implement regular expression matching with support for '.' and '*' where: '.' Matches any single character.​​​​ '*' Matches zero or more of the preceding element. The matching should cover the entire input string (not partial). Constraints: 0 <= s.length <= 20 0 <= p.length <= 30 s contains only lowercase English letters. p contains only lowercase English letters, '.', and '*'. It is guaranteed for each appearance of the character '*', there will be a previous valid character to match.

Insight/Solution: DP problem, pretty complicated but when broken down accordingly, the problem becomes intuitive first dive only into a case using '.' (not '*' yet), this is pretty simple, the recursive expression would be: T, if s[i] == p[j] or p[j] == '.' F, otherwise now we consider this '*' case, recognize that we must have a preceding letter before '*' so there must also be some length condition to check, but as for how it works, the '*' can do two things: negate all of the preceding letter's frequency or keep counting s[i], let's represent them as case *1 and case *2, note that case *2 requires s[i] == p[j] to keep track of the pair of preceding letter and '*', we consider p[j] = preceding letter and p[j + 1] = '*' therefore, our new recursive expression is now if p[j + 1] == '*', return f(s, p[j + 2:]) or (s[i + 1:], p[j + 1:]) else, consider the two cases with only '.' note: the recursive expression is not the only condition we have to check, we also have to ensure '*' comes after a preceding letter (determine via length condition), the only condition we do not care if s[i] == p[j] is for case *1 suggestion: solve using recursion first (main algorithm code in a helper function) and add memoization to the code, extremely simple and intuitive flow of the logic with this explanation compared to the bottom-up approach

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 a 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 nums representing the amount of money of each house, return the maximum amount of money you can rob tonight without alerting the police. Constraints: 1 <= nums.length <= 100 0 <= nums[i] <= 1000

Insight/Solution: DP problem, recognize that there can only be two solutions: either the total amount of money robbed includes the first house but excludes the last house or includes the last house but excludes the first house, whichever total sum is higher is the maximum amount of money we can rob knowing this, we can degenerate this problem into House Robber I where we have inputs nums[1:] and nums[:-1], then take the max of both of them Note: use a helper function to program the House Robber I function

377. Combination Sum IV Given an integer array with all positive numbers and no duplicates, find the number of possible combinations that add up to a positive integer target. Follow up: What if negative numbers are allowed in the given array?How does it change the problem? What limitation we need to add to the question to allow negative numbers?

Insight/Solution: DP problem, should also really be called permutation sum since order of the "combination" does matter, meaning... (1,1,2) is essentially the same as (1,2,1) or (2,1,1) the true combination sum problem is actually 518. Coin Change 2, and the different between the two algorithms is how the loop is nested, and it's easy to see why if the outer loop contains our nums, then the problem is a combination sum problem since we would only calculate the number of combinations we could have for aa certain value once, for the case where the inner loop contains nums, we consider multiple ways to getting to a value as unique from others, so we end up solving permutations instead of combinations Follow-up: with negative numbers, we would end up having an infinite amount of ways to essentially get to 0, so we would need some kind of maximum length limitation to restrict the number of "combinations"

673. Number of Longest Increasing Subsequence Given an integer array nums, return the number of longest increasing subsequences. Notice that the sequence has to be strictly increasing. Constraints: 1 <= nums.length <= 2000 -106 <= nums[i] <= 106

Insight/Solution: DP problem, similar to Longest Increasing Subsequence except we have an extra array to keep track of the number of longest increasing subsequences we do have to modify the inner part of the algorithm, we have to keep track of when we meet a new longest increasing subsequence or if we meet different longest increasing subsequence if length[i] == length[j], this implies that we have an even longer increasing subsequence, so we should update the length and also set count[i] = count[j] (keeps track of all the increasing subsequences), we can do this since we know for sure that nums[i] > nums[j], where j is the pointer that moves around and i is the pointer that points to the end of a subarray if length[i] == length[j] + 1, we know that the subsequence up to j is representing a different increasing subsequence which will also upgrade to be one of the longest increasing subsequences, so we simply do count[i] += count[j]

647. Palindromic Substrings Given a string, your task is to count how many palindromic substrings in this string. The substrings with different start indexes or end indexes are counted as different substrings even they consist of same characters.

Insight/Solution: DP problem, very similar to 5. Longest Palindromic Substring, in fact, the solution is exactly the same except we update our counter of amount of substrings instead of update the longest palindromic substring the recursive expression: dp[i][i] = True dp[i][i + 1] = True dp[i][j] = True, if dp[i + 1][j - 1] and s[i] == s[j] dp[i][j] = False, otherwise there is another solution using two pointers (expand from the center), think of the palindrome as an onion, as you peel its ends, what you have left is just a smaller onion, so if you work towards your center, you keep having smaller and smaller onions so we can start from the center of the substring and make our way towards the ends, keep counting as we form palindromes note that we have two types of palindromes, depending on their lengths: odd-lengths have a center size of 1 character and even-lengths have a center pair of 2 characters, so we can check both each time through a helper function

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.

Insight/Solution: DP problem, we can break up the problem in subproblems by considering the string when they have less characters, perhaps easiest explained using a recursive expression: True, if considering an empty string True, if dp[j] = True and s[j:i] is a valid word False, otherwise dp[j] has to be True since that's how we know that we're maintaining a valid word break

142. Linked List Cycle II Given a linked list, return the node where the cycle begins. If there is no cycle, return null. There is a cycle in a linked list if there is some node in the list that can be reached again by continuously following the next pointer. Internally, pos is used to denote the index of the node that tail's next pointer is connected to. Note that pos is not passed as a parameter. Notice that you should not modify the linked list. Constraints: The number of the nodes in the list is in the range [0, 104]. -105 <= Node.val <= 105 pos is -1 or a valid index in the linked-list. Follow up: Can you solve it using O(1) (i.e. constant) memory?

Insight/Solution: Hash Set and Floyd's Tortoise and Hare Algorithm use a hash set to store all the seen nodes, if a node has already been seen, return it since that node must be the start of the cycle, if the pointer ever points to None, there was no cycle Follow-up: Similar to 287 (Find the Duplicate Number) except the problem is applied to a linked list, simply have the tortoise and hare pointers and iterate until they are equal, this marks the intersection, the proof of the algorithm suggests that the distance from the beginning to the cycle equals the distance from the intersection to the cycle, so reset one of the pointers to the head and move each pointer one by one until they are equal

554. Brick Wall There is a brick wall in front of you. The wall is rectangular and has several rows of bricks. The bricks have the same height but different width. You want to draw a vertical line from the top to the bottom and cross the least bricks. The brick wall is represented by a list of rows. Each row is a list of integers representing the width of each brick in this row from left to right. If your line go through the edge of a brick, then the brick is not considered as crossed. You need to find out how to draw the line to cross the least bricks and return the number of crossed bricks. You cannot draw a line just along one of the two vertical edges of the wall, in which case the line will obviously cross no bricks. Note: The width sum of bricks in different rows are the same and won't exceed INT_MAX. The number of bricks in each row is in range [1,10,000]. The height of wall is in range [1,10,000]. Total number of bricks of the wall won't exceed 20,000.

Insight/Solution: Hash Table, recognize that for each row, we can check which area has an edge if we can sum up to that edge's value, this means we can calculate the number of edges we find and subtract them from the total number of rows, then we'll have the number of bricks we have to pass through, simply take the minimum out of all of them and we have our answer however, we do have an edge case, which is when each row has the same number of bricks with the same width, this means we have to go through all the bricks therefore, we should update min_bricks as min(min_bricks, # of bricks - table[i]), and we have to make sure we do not count the last brick while tallying up our hash table since all the bricks at the end will have edges lined up, which violates the constraint in the description

36. Valid Sudoku Determine if a 9 x 9 Sudoku board is valid. Only the filled cells need to be validated according to the following rules: Each row must contain the digits 1-9 without repetition. Each column must contain the digits 1-9 without repetition. Each of the nine 3 x 3 sub-boxes of the grid must contain the digits 1-9 without repetition. Note: A Sudoku board (partially filled) could be valid but is not necessarily solvable. Only the filled cells need to be validated according to the mentioned rules. Constraints: board.length == 9 board[i].length == 9 board[i][j] is a digit or '.'.

Insight/Solution: Hash set, and while not algorithmic, clean style of code to reiterate, we have three conditions to fulfill if we want to validate an initial sudoku board, and we should handle each condition with its own helper function, this will make the main loop look extremely simple, and in general, the code is very easy to read and follow along there really is no algorithmic thinking here, all you have to do is check if the value was already seen or not using a hash set, I would go for code organization if asked this question, the question is as simple as iterating through each element in a given row or column and checking if the value has already been seen for the nine 3 x 3 sub-box grids, iterate accordingly with appropriate start and end limits, start: 3i and end: 3(i + 1), for i = 0 to 3 since the Sudoku board never changes in size, everything is constant O(1)

49. Group Anagrams Given an array of strings strs, group the anagrams together. You can return the answer in any order. An Anagram is a word or phrase formed by rearranging the letters of a different word or phrase, typically using all the original letters exactly once. Constraints: 1 <= strs.length <= 104 0 <= strs[i].length <= 100 strs[i] consists of lower-case English letters.

Insight/Solution: Hash table (hashing), we can build our own hashing function to store words that are anagrams of each other, then simply return the values of the hash table as a list the key is how we will construct our hash function, we could sort the words and the sorted word is stored as a key, but we can actually do much better by counting the number of letters we see in the word we know that the letters are only lower case English letters, so we could build a fixed array of size 26 where each index represents a letter, so then you can count up the number of each letters and returning a tuple of the end result (summing them up fails, as that just means words of same length will be considered into the same hash key) simply use your newly constructed hash function as a hash key with a hash table, and return the values afterwards as a list

136. Single Number Given a non-empty array of integers nums, every element appears twice except for one. Find that single one. Follow up: Could you implement a solution with a linear runtime complexity and without using extra memory?

Insight/Solution: Hash table or set to store numbers already seen, initialize a count = 0 and add if we haven't seen the number yet, subtract if we have, leftover of count will be our answer Follow-up: Bit manipulation, use the XOR operator i.e. [4,1,2,1,2] -> 4 ^ 1 ^ 2 ^ 1 ^ 2 -> 4 ^ (1 ^ 1) ^ (2 ^ 2) -> 4 ^ 0 ^ 0 -> 4

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.

Insight/Solution: Iterate through the list and if we reach a smaller price than our min_price, change our min_price; else if prices[i] - min_price is greater than max_profit, update max_profit

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.

Insight/Solution: can use either greedy or DP Greedy: locally solve the optimal solution and constantly compare it with the global solution DP: Kadane's Algorithm where f(i) = maximum subarray up to i f(1) = a1 f(i) = ai + max(0, f(i - 1)) Note: DP solution requires O(n) space if we cannot modify the input array

1046. Last Stone Weight We have a collection of stones, each stone has a positive integer weight. Each turn, we choose the two heaviest stones and smash them together. Suppose the stones have weights x and y with x <= y. The result of this smash is: If x == y, both stones are totally destroyed; If x != y, the stone of weight x is totally destroyed, and the stone of weight y has new weight y-x. At the end, there is at most 1 stone left. Return the weight of this stone (or 0 if there are no stones left.) Note: 1 <= stones.length <= 30 1 <= stones[i] <= 1000

Insight/Solution: Max-heap, take the two largest stones, smash them together, and if there is still a leftover stone, put it back into the max-heap Continue to do this until the size of our heap reaches less than size 2, and return whatever stone is leftover if there was 1 stone left, other wise return 0 Note: Python's heap library uses min-heap implementation, we can easily convert it into a max-heap by simply multiplying the values of our stones by -1

160. Intersection of Two Linked Lists Write a program to find the node at which the intersection of two singly linked lists begins. Notes: If the two linked lists have no intersection at all, return null. The linked lists must retain their original structure after the function returns. You may assume there are no cycles anywhere in the entire linked structure. Each value on each linked list is in the range [1, 10^9]. Your code should preferably run in O(n) time and use only O(1) memory.

Insight/Solution: Recognize the commutative property of addition: a + b = b + a = c, so consider pointers headA and headB if headA becomes null, reset to headB, same with headB. headA and headB eventually will reach c together, since if headA reached null before headB, it must go through the same path as headB. the residual will alter headA and headB to mark on same levels. if both end up becoming null together, we know there was no intersection.

654. Maximum Binary Tree You are given an integer array nums with no duplicates. A maximum binary tree can be built recursively from nums using the following algorithm: Create a root node whose value is the maximum value in nums. Recursively build the left subtree on the subarray prefix to the left of the maximum value. Recursively build the right subtree on the subarray suffix to the right of the maximum value. Return the maximum binary tree built from nums. Constraints: 1 <= nums.length <= 1000 0 <= nums[i] <= 1000 All integers in nums are unique.

Insight/Solution: Recursion + DFS or Stack, the problem is easily presentable as a recursive DFS problem, just continue to build these maximum binary trees recursively like so: if l == r return None max_index, max_value = compute_max(nums, l, r) root = TreeNode(max_value) root.left = f(nums, l, max_index) root.right = f(nums, max_index + 1, r) return root # O(n^2) due to computing the max n times using the stack is much trickier but takes O(n) there are two rules for whether we make the node a left child or a right child: 1. suppose we have a current node, and its value is greater than the top of the stack's node's value, then we can pop the stack and the last popped node is the left child of the current node 2. after popping, if there still is a node in the stack, then the current node is a candidate of the top of the stack's right child really tricky... hope to understand it more

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. Note: A leaf is a node with no children.

Insight/Solution: Recursion + DFS, break down the tree into subtrees while also subtracting the sum if root is empty, return False if root.val == sum and root is a leaf, return True return f(root.left, sum - root.val) or f(root.right, sum - root.val)

235. Lowest Common Ancestor of a Binary Search Tree Given a binary search tree (BST), find the lowest common ancestor (LCA) of two given nodes in the BST. According to the definition of LCA on Wikipedia: "The lowest common ancestor is defined between two nodes p and q as the lowest node in T that has both p and q as descendants (where we allow a node to be a descendant of itself)." Constraints: The number of nodes in the tree is in the range [2, 105]. -109 <= Node.val <= 109 All Node.val are unique. p != q p and q will exist in the BST.

Insight/Solution: Recursion + DFS, convince yourself that the LCA is the instant root.val falls in [p.val, q.val] or [q.val, p.val], it is, so the recursive expression is as follows: if p.val < root.val and q.val < root.val, return LCA(root.left, p, q) elif p.val > root.val and q.val > root.val, return LCA(root.right, p, q) return root Note: the root can also be a descendant of itself, meaning it can also be p or q, that is why we don't include <= or >= in the conditions

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.

Insight/Solution: Recursion + DFS, first, travel down the bigger tree via standard dfs, if we find node equal to the value of root of the smaller tree, compare the subtrees. We travel down both subtrees at the same time and if and only if every node is the same then we know we have found the right subtree.

230. Kth Smallest Element in a BST Given a binary search tree, write a function kthSmallest to find the kth smallest element in it. Follow up: What if the BST is modified (insert/delete operations) often and you need to find the kth smallest frequently? How would you optimize the kthSmallest routine? Constraints: The number of elements of the BST is between 1 to 10^4. You may assume k is always valid, 1 ≤ k ≤ BST's total elements.

Insight/Solution: Recursion + DFS, same idea as 98. Validate Binary Search Tree, do an inorder traversal but this time, keep decrementing k until 0, and return the node's value once k = 0 Follow-up: this modification we have to make matches a description of a database, a solution is to do something like an LRU cache and store a doubly linked list as well, something where a node of the BST points to its corresponding node to a doubly linked list which is used for searching this follow-up is more of a design problem, another advanced data structure (which is also used in database managements) is the B+ tree

101. Symmetric Tree Given a binary tree, check whether it is a mirror of itself (ie, symmetric around its center). Follow up: Solve it both recursively and iteratively.

Insight/Solution: a tree is symmetric if left.left == right.right and left.right = right.left, if one of them is null, it is not symmetric, if both are null, it could be symmetric (final condition is to check if the values match) Recursively: pretty simple, just use a helper function where the top call is: isMirror(root, root) Iteratively: similar to BFS, use a queue and follow what we accomplish with the recursive solution

236. Lowest Common Ancestor of a Binary Tree Given a binary tree, find the lowest common ancestor (LCA) of two given nodes in the tree. According to the definition of LCA on Wikipedia: "The lowest common ancestor is defined between two nodes p and q as the lowest node in T that has both p and q as descendants (where we allow a node to be a descendant of itself)." Constraints: The number of nodes in the tree is in the range [2, 105]. -109 <= Node.val <= 109 All Node.val are unique. p != q p and q will exist in the tree.

Insight/Solution: Recursion + DFS, similar to 235 which uses BSTs, except we do not have the special property that BST has so instead, let's take a closer look at the trees, the LCA is the node that is deepest compared to the other CAs, but what does that mean in terms of recursion? it is the first node that joins p and q from different sides, since recursion works such that we go deep, then bubble back up, so if we bubble back up to a node that satisfies the CA condition, we guarantee it is also the LCA the edge happens when one of the descendants is its own ancestor, which we handle that if we find a left node but not a right node (or right node but not a left node), we assume the other node must be in the left subtree or right subtree (whichever was returned), this is because our constraint says p and q exist in the tree, so we would rule that the node we haven't found yet is part of the subtree we would return this question is a logically thinking based problem I would say

100. Same Tree Given the roots of two binary trees p and q, 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. Constraints: The number of nodes in both trees is in the range [0, 100]. -104 <= Node.val <= 104

Insight/Solution: Recursion + DFS, the only way a tree is the same is if both are empty or both have the same value, and they both must have the same tree structure any other time means it is false, so we could set up our recursion as follows if p and q are both empty, return True if only one of them is empty, return False if p.val != q.val, return False once you check all these conditions, return f(p.left, q.left) and f(p.right, q.right)

19. Remove Nth Node From End of List Given the head of a linked list, remove the nth node from the end of the list and return its head. Follow up: Could you do this in one pass?

Insight/Solution: Sentinel Node + two pointers, the question presents itself well as a puzzle, but the edge cases are very difficult to handle unless a sentinel node is used A two-pass algorithm consists of determining the length of the linked list first, then subtracting the length by n, then iterating until the length reaches 0 with another pointer at head, every iteration, we decrement length by 1, once length reaches 0, we simply have our pointer's next point to pointer.next.next Follow-up: Notice that the nth node from the end and the end of the linked list (which we will consider as the null pointer after the last valid node) has a gap of n + 1, so initially, we could iterate only our fast pointer while incrementing a variable gap which is initially set to 0, once gap reaches n + 1, we can start moving our slow pointer, once our fast pointer reaches null, our slow pointer is at the node right before the nth node from the end, so we can simply do slow.next = slow.next.next altogether, we return sentinel.next which handles the edge cases very neatly for us

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 contains a single digit. Add the two numbers and return the sum as a linked list. You may assume the two numbers do not contain any leading zero, except the number 0 itself. Constraints: The number of nodes in each linked list is in the range [1, 100]. 0 <= Node.val <= 9 It is guaranteed that the list represents a number that does not have leading zeros.

Insight/Solution: Sentinel node, this problem is really an issue with edge cases start off with a sentinel node, then keep building the linked list with the sum of both linked list values and a carry, the carry should be set to 1 if the original sum >= 10 otherwise 0, and when we construct the linked list node, we should set the value as total sum (including the carry) % 10, make sure to account for when a linked list is longer than the other, and if the carry ends up pushing to the absolute end of the linked list an example of such edge cases: 2->9 7->8->4 or 2->9 7->8->9

617. Merge Two Binary Trees Given two binary trees and imagine that when you put one of them to cover the other, some nodes of the two trees are overlapped while the others are not. You need to merge them into a new binary tree. The merge rule is that if two nodes overlap, then sum node values up as the new value of the merged node. Otherwise, the NOT null node will be used as the node of new tree. Note: The merging process must start from the root nodes of both trees.

Insight/Solution: Simply perform a DFS that updates a third tree with added values if either node is null, return the non-null node initialize t3 with t1.val + t2.val set t3.left = merge(t1.left, t2.left) set t3.right = merge(t1.right, t2.right)

3. Longest Substring Without Repeating Characters Given a string, find the length of the longest substring without repeating characters. Constraints: 0 <= s.length <= 5 * 104 s consists of English letters, digits, symbols and spaces.

Insight/Solution: Sliding Window + Hash Table, idea is to keep track of which characters we have seen in the hash table, forming a key value pair: {character: index}, keep a starting pointer initially at 0 and length = 0 as we iterate, we check if the character we are on has been seen or not, if it has, we have to also check if the character is actually within our window (which is why we have our value as the index in our key-value pair), so that way, we can check if the character that has been seen is taking into consideration our current window, not a previous window if it is in our current window, we simply move our starting pointer to table[seen character] + 1 (indicating a fresh new window) as we iterate, we always add/update the current character's index in our key-value pair, and update length to be the maximum length it can be

210. Course Schedule II There are a total of n courses you have to take labelled from 0 to n - 1. Some courses may have prerequisites, for example, if prerequisites[i] = [ai, bi] this means you must take the course bi before the course ai. Given the total number of courses numCourses and a list of the prerequisite pairs, return the ordering of courses you should take to finish all courses. If there are many valid answers, return any of them. If it is impossible to finish all courses, return an empty array. Constraints: 1 <= numCourses <= 2000 0 <= prerequisites.length <= numCourses * (numCourses - 1) prerequisites[i].length == 2 0 <= ai, bi < numCourses ai != bi All the pairs [ai, bi] are distinct.

Insight/Solution: Topological Sort, this problem is a topological sort problem in disguise, you can also use Kahn's algorithm which is topological sort using in-degrees

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 104.

Insight/Solution: Sliding Window + Hash Table, the idea is that our substring should contain the letter with the highest frequency since that will maximize our length with our k operations, this is why we use a hash table (or a counter), then we should also consider the case when should we move our left pointer the sliding window case should happen when we know we ran out of k operations, so we move our left pointer to the right by one, however, we also have to keep track of our letter counts, so we will also decrement count[s[i]] by 1, when i = left pointer the condition to check for this sliding window case is if our current window length is greater than the maximum frequency of a character + k, so we should also keep another variable to track the maximum frequency as we iterate throughout the string after we reach the end of our string, i will represent the start of our substring, so we can simply return the length of the string - i to get the length of our maximum substring

159. Longest Substring with At Most Two Distinct Characters Given a string s , find the length of the longest substring t that contains at most 2 distinct characters.

Insight/Solution: Sliding Window + Hash Table, this problem I think is more straightforward than the one with repeating characters, essentially though, you want to keep track of the length of the hash table, once it reaches over 2, we have to find the key-value pair with the smallest index location, remove it, and update our opening window pointer at every iteration, we constantly update the hash table value as we only care about the most recently added letters, and thus we also should constantly update our max_length

209. Minimum Size Subarray Sum Given an array of n positive integers and a positive integer s, find the minimal length of a contiguous subarray of which the sum ≥ s. If there isn't one, return 0 instead. Follow up: If you have figured out the O(n) solution, try coding another solution of which the time complexity is O(n log n).

Insight/Solution: Sliding Window technique, use two pointers to point at the ends of our window, move our end pointer if total_sum < s, otherwise update our min_length, subtract total_sum by nums[start], and move our start pointer, we continuously iterate until our end pointer reaches the end the key behind this algorithm is to not move our two pointers back, only keep them moving forward Follow-up: Using binary search, look into in the future

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: Add one piece of fruit from this tree to your baskets. If you cannot, stop. 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? Note: 1 <= tree.length <= 40000 0 <= tree[i] < tree.length

Insight/Solution: Sliding Window, same problem as 159. Longest Substring with At Most Two Distinct Characters except using integers instead of characters this question prompt is really poorly written, so just read 159's question prompt for effectively the same problem

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. Constraints: The input strings only contain lower case letters. The length of both given strings is in range [1, 10,000].

Insight/Solution: Sliding window + counter + auxiliary state variable, literally the same problem as 438. Find All Anagrams in a String except we return True/False and immediately if one permutation (anagram) was found here, the sliding window will be fixed with the length of s1, our counter will be an array of size 26, all initialized to 0, our auxiliary state will also be set to the length of s1, and our opening pointer set to 0 we set up our counter array such that each character's frequency is counted, i.e. [a: 1, b: 2, c: 0, d: 2, etc...], now we can iterate throughout the string s and maintain the fixed window length every iteration, we decrement the count of the current character in our counter array, notice that the characters in s1 will all be greater than 0, so we know that if its counter value is >= 0 after its decrement, we know that we should update our auxiliary state variable since that means we have a one less character to consider for our window if our auxiliary state variable reaches 0, we know that we've found a window that is a permutation of s1 afterwards, we have to check if our window's length == len(s1), and if it is, we have to update our array counter by 1 for the current letter we are on, also update our auxiliary state variable accordingly (ensuring that we only update the letters in s1), and move our opening pointer by 1

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.

Insight/Solution: Sliding window + counter + auxiliary state variable, this problem uses a fixed sliding window since words are anagrams if they follow two principles: the length are the same, and the frequencies of each letter in the words are the same here, the sliding window will be fixed with the length of p, our counter will be an array of size 26, all initialized to 0, our auxiliary state will also be set to the length of p, and our opening pointer set to 0 we set up our counter array such that each character's frequency is counted, i.e. [a: 1, b: 2, c: 0, d: 2, etc...], now we can iterate throughout the string s and maintain the fixed window length every iteration, we decrement the count of the current character in our counter array, notice that the characters in p will all be greater than 0, so we know that if its counter value is >= 0 after its decrement, we know that we should update our auxiliary state variable since that means we have a one less character to consider for our window if our auxiliary state variable reaches 0, we know that we've found a window that is an anagram of p afterwards, we have to check if our window's length == len(p), and if it is, we have to update our array counter by 1 for the current letter we are on, also update our auxiliary state variable accordingly (ensuring that we only update the letters in p), and move our opening pointer by 1

76. Minimum Window Substring Given two strings s and t, return the minimum window in s which will contain all the characters in t. If there is no such window in s that covers all characters in t, return the empty string "". Note that If there is such a window, it is guaranteed that there will always be only one unique minimum window in s. Constraints: 1 <= s.length, t.length <= 105 s and t consist of English letters. Follow up: Could you find an algorithm that runs in O(n) time?

Insight/Solution: Sliding window + hash table + auxiliary state variable, but let's first go over the brute force solution Brute force: find all the substrings and simply check if the characters in t are in the substring, should take O(S^3) Sliding Window: optimized to O(S + T), this problem is very similar to permutation in string and find all anagrams in a string, the idea is to keep the auxiliary state variable and decrement it whenever we land on a character that has yet to be decremented in our hash table, then we also keep track of a min_length and min_window to keep track of the minimum substring a difference we see for this problem compared to permutation in string and find all anagrams in a string is that our window size can vary, meaning we have to accommodate our logic to handle a window with characters that do not belong in the t string, which is okay (instead of an if statement, use a while loop)

141. Linked List Cycle Given head, the head of a linked list, determine if the linked list has a cycle in it. There is a cycle in a linked list if there is some node in the list that can be reached again by continuously following the next pointer. Internally, pos is used to denote the index of the node that tail's next pointer is connected to. Note that pos is not passed as a parameter. Return true if there is a cycle in the linked list. Otherwise, return false.

Insight/Solution: Slow and fast pointers, the fast pointer starts one node after the slow node and moves one extra node further each time if slow == fast: there is a cycle if fast is null or fast.next is null, there is no cycle

217. Contains Duplicate Given an array of integers, find if the array contains any duplicates. Your function should return true if any value appears at least twice in the array, and it should return false if every element is distinct.

Insight/Solution: Sort or use a hash table/hash set, for sort check if adjacent elements are equal, for set check if it is already in the set sorting is O(nlgn) and hash table/hash set is O(n)

268. Missing Number Given an array nums containing n distinct numbers in the range [0, n], return the only number in the range that is missing from the array. Follow up: Could you implement a solution using only O(1) extra space complexity and O(n) runtime complexity?

Insight/Solution: Sort, Hash Set, bit manipulation, Gauss' Formula Follow-up: bit manipulation and Gauss' Formula handle this follow-up, for bit manipulation, recognize that there is guaranteed a missing number, but we can collect all the numbers of the range from our index and length of the nums (if the missing number is simply n), then any number that is not missing can be shown twice, while the missing number is shown once, using the XOR operator, a ^ a = 0, b ^ 0 = b, and it has the commutative property as well, so simply XORing will yield the correct solution

234. Palindrome Linked List Given a singly linked list, determine if it is a palindrome. Follow up: Could you do it in O(n) time and O(1) space?

Insight/Solution: Store node values in an array and check if the reverse is the same as the original Follow up: Two pointers + reverse linked list, we have a slow and fast pointer, iterate until fast or fast.next is null, then reverse the linked list at slow, then reset fast to head, then iterate and check if fast and slow are the same

543. Diameter of a 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. Note: The length of path between two nodes is represented by the number of edges between them.

Insight/Solution: The idea is to use DFS which will bring the diameter to us as a side effect We calculate the depth of a tree, where we actually start with a depth of -1 for a solo tree node. Build up the left and right subtree depths + 1, sum them together for our diameter. However, we should return the max of depths for left and right, since the diameter encompasses both paths, while we can only account for one full path when returning.

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. You may assume that the array is non-empty and the majority element always exist in the array.

Insight/Solution: There are multiple solutions, but we'll go over 3 solutions Sorting: sort and return the middle element, runtime: O(nlgn), space: O(1) or O(n) Hash Table: map each element and have a counter, the element with the highest count is returned, runtime: O(n), space: O(n) Boyer-Moore Voting Algorithm: Assume the first element is the majority element (call it candidate) and set count = 0, every time we see a match in our list, we increment count by 1, -1 if not a match, when we reach count = 0, reset our candidate, our candidate at the end will be the majority element, runtime: O(n), space: O(1)

269. Alien Dictionary There is a new alien language that uses the English alphabet. However, the order among letters are unknown to you. You are given a list of strings words from the dictionary, where words are sorted lexicographically by the rules of this new language. Derive the order of letters in this language, and return it. If the given input is invalid, return "". If there are multiple valid solutions, return any of them. Constraints: 1 <= words.length <= 100 1 <= words[i].length <= 100 words[i] consists of only lowercase English letters.

Insight/Solution: Topological Sort, there are two steps to solving this hard LC problem 1. build a DAG 2. topological sort simple idea, difficult execution, the difficulty comes from building the DAG and handling some interesting edge cases, understand what it means for a word to be lexicographically correct, here is an example: abc, zebra, zoo z > o but lexicographically cares about the order of words, not individual letters, we should only care about letters at its individual level for an example like this: wrt, wrf --> this means t comes before f an edge case to consider is abc, ab which the expected outcome is an empty string if abc is before ab, then c must have some negative order value which doesn't make sense, so we declare this test case invalid using Kahn's algorithm with ascii value indexing will be efficient, easy, and clean

199. Binary Tree Right Side View Given a binary tree, imagine yourself standing on the right side of it, return the values of the nodes you can see ordered from top to bottom.

Insight/Solution: Tree + BFS, conduct a level order traversal and the last node in each level is the node we see from the right side

105. Construct Binary Tree from Preorder and Inorder Traversal Given preorder and inorder traversal of a tree, construct the binary tree. Note:You may assume that duplicates do not exist in the tree.

Insight/Solution: Tree + DFS + Queue + Hash Table, the theory is that preorder goes root -> left -> right, and inorder goes left -> root -> right what this means in the arrays is the first node in the preorder array is our root, and the subarray to the left of that value in the inorder array is a left subtree of the root, same goes for the right subarray consider the preorder: [20, 15, 7] and inorder: [15, 20, 7], this means that 20 is the root, 15 is the left subtree, and 7 is the right subtree how to handle the preorder condition? this is where the queue and DFS comes into play, we have to use queue's popleft property to pop off the first element of the preorder array, and we have to use DFS so that we maintain our mutable array throughout our recursive path, if we have a larger tree to consider such as preorder: [3,9,20,15,7] and inorder: [9,3,15,20,7], you'll notice that we want to consider the right subtree once we pop off everything to the left subtree as well, this is why we must do DFS so that we take advantage of the mutable property that lists have in python use a hash table to keep track of where each element of inorder is, we use the index that we get as a way to split up our array into subproblems and eventually reach a base case to terminate our recursion Note: implement the algorithm with just DFS first, then make the small adjustments to optimize

98. Validate Binary Search Tree Given the root of a binary tree, determine if it is a valid binary search tree (BST). A valid 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.

Insight/Solution: Tree + DFS, one key principle about BSTs is that its inorder traversal yields a sorted output, so if we conduct an inorder traversal, we can simply check if the previous value was smaller than the current value remember that the inorder traversal follows the rule: left->root->right, you can solve this iteratively or recursively, but if done iteratively, use the stack data structure

283. Move Zeroes Given an array nums, write a function to move all 0's to the end of it while maintaining the relative order of the non-zero elements. Note: You must do this in-place without making a copy of the array. Minimize the total number of operations.

Insight/Solution: Two pointers + invariant Invariant: all the elements left of the slow pointer are non-zero numbers, everything in between the slow and fast pointers are zeroes

79. Word Search Given an m x n board and a word, find if the word exists in the grid. The word can be constructed from letters of sequentially adjacent cells, where "adjacent" cells are horizontally or vertically neighboring. The same letter cell may not be used more than once. Constraints: m == board.length n = board[i].length 1 <= m, n <= 200 1 <= word.length <= 103 board and word consists only of lowercase and uppercase English letters.

Insight/Solution: Use DFS/backtracking, we have the backtracking function return a boolean, indicating whether we have a match or not, a match is happened if we run out of letters to search for, any time we go out of the board or letters don't match we return false we have to use backtracking so we don't accidentally go back to our previous letter, use a character like '*', and revert back to the original letter after backtracking, this means we should store our current letter in a temp variable afterwards, return the matched boolean variable, if it trickles back to the top as true, we found a word match

179. Largest Number Given a list of non-negative integers nums, arrange them such that they form the largest number. Note: The result may be very large, so you need to return a string instead of an integer.

Insight/Solution: Use a custom comparator and sort, here is a proof by contradiction: suppose a ~ b > b ~ a, and we want to produce an incorrect order, so assume there is a c such that b precedes c but c precedes a, this is impossible because if b ~ c > c ~ a, then a ~ c must be > c ~ a, and so transitivity is maintained in Python3, the default comparator is the __lt__ comparator, so we have to modify that one def__lt__(s1, s2): return s1 + s2 > s2 + s1

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.

Insight/Solution: Use a sentinel node and update accordingly while l1 and l2 Note: remember to add the last node after the while loop iteration and return the next node of our sentinel node

242. Valid Anagram Given two strings s and t , write a function to determine if t is an anagram of s. Note:You may assume the string contains only lowercase alphabets. Follow up: What if the inputs contain unicode characters? How would you adapt your solution to such case?

Insight/Solution: Use an array of size 26 to keep track of counts, the index is based off the character, so we start at 'a' = 0 -> 'z' = 25, for every iteration of a letter for s and t, we increment by 1 and decrement by 1, respectively iterate through the array again and if we find a value not equal to 0, we know it means s and t were not anagrams Follow-up: use a hash table instead of a fixed-size array

261. Graph Valid Tree Given n nodes labeled from 0 to n-1 and a list of undirected edges (each edge is a pair of nodes), write a function to check whether these edges make up a valid tree. Note: you can assume that no duplicate edges will appear in edges. Since all edges are undirected, [0,1] is the same as [1,0] and thus will not appear together in edges.

Insight/Solution: Very similar problem to Course Schedule with a few more constraints, in graph theory, a graph is also a tree with the following: - the graph must be acyclic - the graph must be connected in Course Schedule, we already handled the cycle detection, in addition, we have to check if we visit all nodes or not (therefore, we should only call DFS once), and since we consider the graph undirected, we also have to pass an extra parameter (parent) to check if our vertex is a parent (if so, we should not consider it, or else our algorithm will consider it a cycle)

1. Two Sum Given an array of integers nums and an integer target, return indices of the two numbers such that they add up to target.

Insight/Solution: a + b = x, so use a hash table to check if b = x - a is in it

704. Binary Search Given a sorted (in ascending order) integer array nums of n elements and a target value, write a function to search target in nums. If target exists, then return its index, otherwise return -1. Note: You may assume that all elements in nums are unique. n will be in the range [1, 10000]. The value of each element in nums will be in the range [-9999, 9999].

Insight/Solution: binary search

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. Note: You may assume k is always valid, 1 ≤ k ≤ array's length.

Insight/Solution: heap, can actually be solved using either a max heap or min heap, but using a min heap will be optimal with a max heap: initialize a max heap with the nums and pop the heap k times, and the kth element is the answer with a min heap: initialize an empty heap and construct a min heap with the values, but as we keep adding them, we also pop out values if our min heap's size exceeds k, this effectively will maintain the largest elements of the heap up to size k, and we can just pop once more after iterating to get the kth largest element Note: python's heapq module includes a function that does this already: heapq.nlargest(k, nums) which outputs an array sorted in descending order, there is also a function for smallest (heap.nsmallest) analysis: max-heap's time and space complexities are as follows: O(nlgn) and O(n), for the min-heap, they are as follows: O(nlgk) and O(k) There is in fact an even better solution in O(n) and O(1), it is a divide and conquer technique called Hoare's selection algorithm (Quickselect), something Professor Miguel also taught to us, need to look in the future and implement using this algorithm

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]. Constraint: It's guaranteed that the product of the elements of any prefix or suffix of the array (including the whole array) fits in a 32 bit integer. Note: Please solve it without division and in O(n). Follow up: Could you solve it with constant space complexity? (The output array does not count as extra space for the purpose of space complexity analysis.)

Insight/Solution: left and right product lists, we basically construct an array for the product of numbers to an element's left and it's right, afterwards, multiply each element at left with the corresponding right and store into an output array Follow-up: same approach as before, except we don't store the products in an array, instead, we multiply an integer variable as we move forward, so suppose we start with our left products, then as we move along our output array, we set it to left, then multiply left by the current location we are at (use an example, it will make more sense), do the same approach with right products except we go in reverse and multiply output[i] with right, not set output[i] = right Note: the two extremes at the end only require a product from one side, the far left element does not have any left products, the far right element does not have any right products, use 1 as a fill-in value due to the identity property of multiplication

152. Maximum Product Subarray Given an integer array nums, find the contiguous subarray within an array (containing at least one number) which has the largest product.

Insight/Solution: one of those weird DP/greedy problems, we keep track of local solutions and build our global solution off the local solutions Similar idea to the maximum subarray problem, except we handle products which have a twist, the twist has to do with handling two cases: zeroes and negative numbers recall that the greedy choice in the maximum subarray problem was local_max = max(num, num + local_max) global_max = max(local_max, global_max) the idea is a great start, so consider for this problem the greedy choice foundation local_max = max(num, num * local_max) global_max = max(local_max, global_max) handling negative numbers means there is a potential for a local_max to suddenly switch to being the smallest product, and the opposite is true too, the smallest product can suddenly switch to being the largest product, so it would be wise to keep track of the smallest products as well, and consider their product with num as another condition for checking the max so now we have local_max = max(num, num * local_max, num * local_min) local_min = min(num, num * local_max, num * local_min) global_max = max(local_max, global_max) zeroes are handled accordingly with the condition of checking num and multiplying by num, that will effectively reset our multiplication chain and start fresh for the next number, our global_max will still hold onto the max product we solved before the zero, so if there is an even larger max product after the zero, our third line for computing the global_max will handle that case accordingly

20. Valid Parentheses Given a string s containing just the characters '(', ')', '{', '}', '[' and ']', determine if the input string is valid. An input string is valid if: Open brackets must be closed by the same type of brackets. Open brackets must be closed in the correct order.

Insight/Solution: the idea is that the most recent open parenthesis will match the first closing parenthesis, hence we can use a LIFO data structure Use a stack to add all the open parentheses and pop whenever we hit a closed parenthesis.

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? Constraints: The input prerequisites is a graph represented by a list of edges, not adjacency matrices. Read more about how a graph is represented. You may assume that there are no duplicate edges in the input prerequisites. 1 <= numCourses <= 10^5

Insight/Solution: this problem is disguised as a graph cycle detection problem, recognize that we could build our pairs as a directed graph Notice that we can have disconnected graphs, and that we only fail to complete all courses if there is a cycle, use DFS with the labeling of -1, 0, and 1 instead 0 = unvisited -1 = visiting 1 = visited this is important to note because if we had done a standard T/F method, our algorithm will allow some edges to be considered as a cycle (which may or may not be true)

226. Invert Binary Tree Invert a binary tree.

Insight/Solution: very easily done via recursion (idea that trees have subtrees, if they have children) if the head is null, return it head->left = inverse of head->right head->right = inverse of head->left can do this in one line with python

287. Find the Duplicate Number Given an array of integers nums containing n + 1 integers where each integer is in the range [1, n] inclusive. There is only one duplicate number in nums, return this duplicate number. Follow-ups: How can we prove that at least one duplicate number must exist in nums? Can you solve the problem without modifying the array nums? Can you solve the problem using only constant, O(1) extra space? Can you solve the problem with runtime complexity less than O(n2)? Constraints: 2 <= n <= 3 * 104 nums.length == n + 1 1 <= nums[i] <= n All the integers in nums appear only once except for precisely one integer which appears two or more times.

Insight/Solution: we'll break up the solutions by their follow-ups: you can sort the list and check for adjacent duplicates 1.) pigeonhole principle, if n objects are put into m containers, and n > m, then there will be at least one container with multiple objects 2). since sorting will modify the list, we can use a hash set instead to store the numbers we have seen in the array 3). since using a hash set means we use space, we have to opt for a different algorithm, this one allows for the brute force, so simply run a nested for-loop 4). rip, they said now make it faster, we can use Floyd's Tortoise and Hare algorithm (phase 1: tortoise = nums[tortoise], hare = nums[nums[hare]], phase 2: both move at the same pace), essentially, we treat the value of our array as pointers to nodes


Related study sets

MKTG 310 Principles of Marketing

View Set

Disability Income and Related Insurance

View Set

Chapter 28 - Head and Spine Injuries

View Set

Health Promotion and Maintenance (#1)

View Set

Combo with "AIS Chapter 8" and 8 others

View Set

American Government 310L: Exam One!

View Set

11.1.3 practice questions CIS 53

View Set