Algo Solution Approaches Flashcards
(63 cards)
Make Array Zero by Subtracting Equal Amounts
Count number of distinct non zero values and return that number since each operation removes the current smallest positive element from all.
let set = new Set(nums)
return set.has(0) ? set.size - 1 : set.size
Copy list with random pointer
Use hashmap to map original nodes to new nodes in first pass, then set next and random pointers on second pass.
while (current)
nodeMap.get(current).next = nodeMap.get(current.next) || null
nodeMap.get(current).random = nodeMap.get(current.random) || null
Reorganize string
Count character frequencies. If any character freq exceeds (n+1)/2 then return “” because not possible.
maxCount = Math.max(…freq.values()
if (maxCount > Math.ceil(s.length / 2) return “”
Push all [character, count] into heap (heapify up after each one) then while the heap has elements pop off two at a time, push both in result, then if freq - 1 is more than 0, push them back on the heap [character, count - 1)
When one char left, push to result, return result.join
Word Break II
Use backtracking and memoization/DP.
Iterate over string and when prefix matched a dictionary word recursively process the remainder and cache results.
Memo is Map() and also keep a word Set()
DFS method takes index. Base case is when index === string length return empty string. Second base case when memo has the index as a key return that value.
Otherwise initialize result array. For loop from start idx + 1 and go for length of string. Prefix variable is s.slice(start, end). If word set has that prefix then make a suffixes variable = to recursive call passing in end idx. Loop through suffixes and push to results
results.push(suffix === “” ? prefix : prefix + “ “ + suffix)
Outside of loop memo.set(start idx, results)
Return results
Outside dfs return dfs(0)
All nodes K distance in binary tree
Find target node and create parent map (map that store parents for each node) {node: parent}
const buildParentMap = (node, parent, map) => if !node return
if parent != null map.set(node, parent)
//recursive call
buildParentMap(node.left, parent, map)
buildParentMap(node.right, parent, map)
Preorder traversal
Set distance variable, queue = [target], visited set()
While queue length. If distance === k return queue.map(node => node.val (each new level is one more distance, so each loop adds one)
Set queue size and iterate through. Shift off a node and push children to visited and queue, if parent from parent map isn’t in visited, add to visited and queue. Increment distance
Rotting oranges
Multi source BFS on each rotten orange. Keep track of time and fresh as we spread rotten.
so make directions and queue, count time and number of fresh oranges. Nested loop through grid increment fresh for 1s and push rotten to queue with 2s
While fresh exist and queue has elements, set queue size and iterate through. Pop off a square [row, col] then iterate through directions and get new row and new col. if that square is 1 (fresh) then push to queue, set it to 2, decrement fresh. Outside of the for loop, increment time before next queue loop.
Return fresh === 0 ? time : -1
Integer to English Words
String formatting / divide and conquer. Keep an array of words and then break up n by groups of three
<20 [“”, “one”, “two”…”nineteen”
10s [“”, “”, “twenty”, “thirty”…”ninety”
thousands [“”, “thousand”, “million”, “billion”
Helper function with long if/else (if n < 20 do index of <20 list, if n < 100 do 10s[Math.floor n/10 + “ “ + helper(n%10), else below20[math floor n/100 + “Hundred” + helper(n%100)
Under helper function i = 0, while num>0 if num%1000 != 0 res = heloer(num%1000 + thousands[i] + “ “ + res
Num = math floor num/1000
i++
Return res.trim()
LRU Cache
See other card for Map() version. In doubly linked list version it’s the same except we use linked list methods to add and remove nodes
Max Robots within budget
Sliding window + monotonic queue (orders elements ascending or non). Use prefix sum to make prefix sum array from running costs. Then use sliding window to calculate the cost of the whole array.
First keep track of longest charge time in the window with the monotonic queue and a while loop (so only the longest charge time stays in the queue at any given time)
Set k/window size to r-l+1
Total running cost is prefix formula prefix[r+1] - prefix[l]
Cost = charge time (dequeue[0]) + k * total running
While cost > budget
If dequeue[0] < left then shift
Left++
Recalculate window size, total running cost, and cost
Still in for loop res= math max of res, left - right + 1
Outside loop return res
Find triangular sum of array
Basically while loop through creating new and smaller arrays. Can use for loop, map, or reduce
while array length > 1
newArr = []
For loop
newArr.push(arr [i] + arr[i +1])
arr = newArr
OR
arr = arr.slice(1).map((val, i) => (val + arr[i]) % 10) this removes the first element from the array each loop
OR
arr = arr.reduce((newArr, cur, i, a) => {
If i < a.length
newArr.push((cur + a[i+1]) % 10)
Return newArr }, [])
THEN return arr[0] last element
Valid Palindrome (Meta)
Two Pointers O(n), O(1)
Need to remove nonalphanumeric characters with regex (/[a-zA-Z0-9]/g) or isLetterOrDigit() method that checks character codes, then move pointers from outside to center returning false if they don’t match. Return true after they all match.
Merge Sorted Arrays (Meta)
Three Pointers O(m + n), O(1)
Three pointers at last nonzero digit of nums1, last digit of nums2, and last index of nums1. Go backward in for loop, using i the last pointer, make sure second pointer is in range then regular comparison of merge sort.
Valid Palindrome II (Meta)
Two pointers O(n), O(1)
Make a regular isPalindrome helper function. Then outside the helper, initialize two pointers and move inward (just like in helper), but when there is a mismatch, check both options (removing the element at l or the one around r) by invoking the helper function. Can also probably do recursively
Two Sum (Meta)
Cache / Hash O(n), O(n)
Create a cache to keep the numbers already seen and their indices. With each number, check if the cache has the difference of that number and the target. If so, just return the value of that entry in the cache, along with the current index i. If not, add that number to the cache as the key with it’s index as the value.
Diameter of a Binary Tree (Meta)
Post order DFS O(n) or O(log(n)), O(n)
Make a dfs helper that takes in root. No root is base case to return zero. Go in PostOrder, so recursively call left, then recursively call right, then see if left + right is greater or less than current result. Return from helper 1 + the max of left and right (because it’s the current longest path). Invoke helper with root, return res
Range Sum of BST (Meta)
Tree DFS Recursive or iterative O(n), O(n)
Can do dfs recursively or iteratively with a stack. Order doesn’t matter for this one. While the root has value or the stack has elements, you’ll see if the current node value is in between the low and high and if so add it to sum. Then for the left child you can call it recursively or push to stack if the val is of the current node is greater than low (if it’s not you know the left child will be even less). Then same for the right child.
Valid Word Abbreviation (Meta)
Two Pointers O(n + m), O(1)
Two pointers to traverse the word and abbr. While loop as long as both are less than word/abbr respectively. Check if the abbr char is a number or not with isNaN(). if it’s not a number check if it matches the corresponding word char. If not return false. If yes, increment both pointers. If the char was a number, then we check if it’s ‘0’. If so return false. If not, do while loop as long as current abbr char is a number. Add together by num = num * 10 + (parseInt(abbr[j])). Move the word pointer by num spaces. If the new pointer is longer than word length return false. If not, continue in while loop. Return true if both pointers === word and abbr lengths respectively.
Minimum Remove to Make Valid Parentheses (Meta)
Stack O(n), O(n)
“This solution needs two passes: one to validate parens and identify which need to be removed, and another to build a new string without the invalid parens. Will usually need two passes if the operation on one element depends on later elements. Do regular validation with stack, except add index instead of “”(“”. On closing paren, if stack has length, pop off, if not, add current i to a Set of indices to remove. After first pass, add the remaining indices in the stack to the Set. In second pass add characters to a new array if the Set doesn’t have their index. Join the array to a string and return. “
Binary Tree Vertical Order Traversal (Meta)
BFS / Queue O(n), O(n)
We need to traverse the BST level by level, so this is BFS with a queue. Create queue to add nodes to, and a map to match columns with values. Add each [col, node] to the queue, starting with [0, root]. For each [col, node] pair, add the col to map as a key with value of [], then push node.val to the array. Then if there is a left node, add it to queue with col - 1, if there is a right node, add it to queue, with col + 1. Use the map to make a results array in order of the map keys with the values as the result array elements.
OPTIMIZE: by using an i pointer and while (i < queue.length) instead of while (queue.length) we can avoid using the shift method. By keeping track of a minCol and maxCol and updating with each new loop we can then loop from minCol-maxCol in a for loop instead of sorting the map keys.
Basic Calculator II (Meta)
Stack O(n), O(n)
“Create a stack and a lastOperator variable set to ‘+’. Start iterating through the string, skipping whitespace. When an integer is evaluated then act based on the lastOperator. ‘+’ push to stack, ‘-‘ push negative to stack, ‘*’ pop off stack and multiply to num then push result back on stack, ‘/’ pop off stack and divide by num then push Math.trunc result back on stack. If it’s not white space or an integer, it’s an operator so set lastOperator variable. After the whole string is evaluated, sum up numbers in stack and return sum.
OPTIMIZE: can optimize space by not using a stack and instead keeping track of currentNum and lastNum, adding lastNum to a result for ‘+’ and ‘-‘, and operating on lastNum for ‘*’ and ‘/’”
Kth Largest Element in an Array (Meta)
Min Heap O(n log k), O(k)
Implement a min heap with array. Create heapifyUp and heapifyDown helper functions. Iterate through array. If min heap length is less than k, just push to heap and heapifyUp. If heap already has k elements, check if the current number is greater than minHeap[0]. If it is, replace minHeap[0] with num and heapifyDown. At the end of the loop return minHeap[0]
Lowest Common Ancestor of a Binary Tree (Meta)
Post order DFS O(n), O(n)
This one is a bit harder than for BST. We can’t automatically determine whether to go left or right so we need to keep the evaluated result of the recursive calls in left and right variables. We don’t actually need to find each node. We know they are both in the tree, so we just need to find one of them. If just one of the left or right is not null, that is the LCA so we return it. If both the left and right calls have values then that means they were found on either side of the root, so the current root is LCA.
Lowest Common Ancestor of a Binary Tree III (Meta)
Two Pointers O(n), O(n)
Since we have parents for this one, we can start at the two nodes and work up, this makes it easier. No need to do DFS, we can just set a pointer a to the p input and a pointer b to the q input. Then while they are not equal we just keep moving them up by setting the pointer to it’s parent, or if the parent is null, to the other pointers starting point (p or q). Eventually they will meet at the LCA and break the loop.
Random Pick with Weight (Meta, Google)
Prefix Sum O(log n), O(n)
For optimal use a prefix sum array for weights (no zeroth element extra) and then pick a random index between 0 and the sum of weights. Then use a binary search to find that index of the weights