Name 4 enumeration use cases for backtracking
What algorithm does backtracking use and what’s a “must have” function for backtracking
What are the two implementations of a graph
Name 2 diff between graph vs tree traversal
What data structures are used for BFS vs DFS
BFS uses a Queue (class LinkedList)
DFS uses a Stack (class Stack)
Describe BFS to visit all vertices for a graph (iterative approach)
Describe DFS for a graph (iterative approach)
Describe DFS for graph using recursion and some things to note
procedure dfs(vertex v) {
visit(v);
for each neighbor u of v
if u is undiscovered
call dfs(u);
}Name 4 DFS applications (1 of which is not studied so it’s ok to only name 3)
Tradeoffs between DFS and BFS (incomplete)
BFS
- can consume a lot more memory when the branching factor of a tree is huge
DFS
- can take a long time to visit other neighboring nodes if the depth of the tree is huge
Advantage of using adjacency list over adjacency matrix
Implement permutation using backtrack
Highlights (compare to the subsets)
- add to solution only if the length matches
- no need to have a start pointer
- need to check if the current item is already in visited
/**
* This implementation does not handle the input if it contains duplicate values
* input: 1, 2, 3,
* output: [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]
*
* https://leetcode.com/problems/permutations/
*
* @param nums
* @return
*/
public List<List<Integer>> permute(int[] nums) {
List<List<Integer>> solution = new ArrayList<>();
permuteBacktrack(solution, new ArrayList<>(), nums);
return solution;
}
private void permuteBacktrack(List<List<Integer>> solution, List<Integer> visited, int [] nums) {
if(visited.size() == nums.length){
solution.add(new ArrayList<>(visited));
}
for(int i = 0; i < nums.length; i++){
if(visited.contains(nums[i])) continue; // element already exists, skip
visited.add(nums[i]);
permuteBacktrack(solution, visited, nums);
visited.remove(visited.size() - 1);
}
}Implement subsets using backtrack
Algorithm highlights:
- because we use recursion, any temp data structure are passed in as args instead of return values
- args are: solution, visited (list), input (array), start pointer
- have a for loop to iterate thru the input array
- visit the current item
- recursion with start++
- remove the last item in visited
- essentially “visited” is used as a “stack”
public List<List<Integer>> subsets(int[] nums) {
List<List<Integer>> solution = new ArrayList<>();
subsetsBacktrack(solution, new ArrayList<>(), nums, 0);
return solution;
}
private void subsetsBacktrack(List<List<Integer>> solution , List<Integer> visited, int [] nums, int start){
solution.add(new ArrayList<>(visited));
for(int i = start; i < nums.length; i++){
visited.add(nums[i]);
subsetsBacktrack(solution, visited, nums, i + 1);
visited.remove(visited.size() - 1);
}
}Find substring problem - high level description of the approach
Problem: find a min substring in s that satisfies t
* Input: s = "ADOBECODEBANC", t = "ABC" * Output: "BANC"
Find substring problem - what are the data to keep track of
Problem: find a min substring in s that satisfies t
* Input: s = "ADOBECODEBANC", t = "ABC" * Output: "BANC"
Implement isPalindrome
public boolean isPalindrome(String s, int low, int high){
while(low < high)
if(s.charAt(low++) != s.charAt(high--)) return false;
return true;
}Important points
- use s.charAt()
- while (low < high), not <= because no need to compare the middle char if length is odd
Implement the template for binary search
- how to compare left and right (< or <=)
- mid rounds up or down, in java, what method to call
- how to set mid pointer
- how to set left and right after each iteration
- after exiting the loop, which pointer do we return
def binary_search(array) -> int:
def condition(value) -> bool:
pass
left, right = min(search_space), max(search_space) # could be [0, n], [1, n] etc. Depends on problem
while left < right:
mid = left + (right - left) // 2 # means round down
if condition(mid):
right = mid
else:
left = mid + 1
return leftName 3 basic applications for binary search
Basic applications
When can we use binary search
Give a sample problem of an advanced application
In this sample problem, what are the min and max values for the search space
When we can identify a search space.
Sample problem - determine the min ship weight to ship all the shipments within x days.
Input: weights = [1,2,3,4,5,6,7,8,9,10], days = 5
Approach
- search space is left = max(weights), right = sum(weights)
- condition function returns true if it’s possible to ship everything within D days with a given capacity
What are the variations of the sliding window problem
“max” window
- the initial condition is valid
- goal is to find the “max” window
- example: find max non repeated chars in a string
“min” window
- the initial condition is invalid
- goal is to find the “min” window where it’s valid
- example: find the substring problem
What are the two implementations of the “max window” problem
“shrinkable” solution
- right pointer expands until the window is invalid
- then shrink the left pointer until it’s valid again
- keep track of the “max” result
“non shrinkable” solution
- based on the observation that once we find a “max” value so far, then there is no need to shrink it
- we “shift” the window by incrementing “left” pointer when the window is invalid
- note there is no inner loop, it’s an “if” statement instead
- this essentially “shifts” the window (without increasing the size) when it’s invalid, thus keep track of the “max result” seen so far
Some highlights of the sliding window implementation for both the “max”and the “min” variations
common
- outer loop is a for loop, “right” ptr moves 1 step every time
- inner loop is a while loop, “left” ptr moves 1 step while its valid or invalid
- the variation between problems is how to keep the “state”
“max window”
- because the window starts as valid, the outer loop expands the window while state is valid
- the inner loop shrinks the window until it’s invalid
“min window” is the opposite
In union find, what’s the difference in the data stored in the “root” data structure between the quick find and quick union implementations
Whats union find and what are the 4 common operations