Array and Hashing

Two Pointers

Sliding Window

  • Best Time to Buy and Sell Stock ✅ 2023-07-23
  • Longest Substring Without Repeating Characters ✅ 2023-08-04
    • Map/Set for checking duplicate
  • Longest Repeating Character Replacement ✅ 2023-08-05
    • Keep track of the maximum character count (max_frequency)
    • Substring is valid if r - l + 1 - MaxFrequency <= k
    • result = maxFrequency + k
    • No need to recompute/reduce max_frequency since a smaller value must results in a shorter substring
  • Minimum Window Substring ✅ 2023-08-12
    • Hash map to keep track of the characters of target substring
    • Expand right pointer until substring is valid, then expand left pointer until substring is invalid, at the same time updating the result
    • sCount to determine if the substring is valid by increasing sCount only if sMap[s[r]] <= tMap[s[r]], i.e. sCount is the number of characters in sMap that satisfy the requirement in tMap.
    • sCount == tCount can be used to control the while loop for increasing the left pointer, we decrease sCount if it no longer meets the requirement in tMap

Stack

  • Valid Parentheses ✅ 2023-07-30
    • Stack and map to pop opening parentheses when they matched
    • Stack would be empty if it is valid
  • Min Stack ✅ 2023-07-31
    • Linked list implementation of stack
    • Extra variable to store the minimum value at a specific level
  • Evaluate Reverse Polish Notation ✅ 2023-09-02
    • Pop operands when operator is met, push the result back to the stack
  • Generate Parentheses ✅ 2023-09-01
    • DFS and maintain the number of available open and close parentheses
    • Recurse if there are available open parentheses or an open parentheses can be closed by an close parentheses, i.e. openCount > closeCount, i.e. openAvailable < closeAvailable
  • Daily Temperatures ✅ 2023-09-02
    • Maintain a stack of indices, pop while new temperature is greater than top, i.e. a monotonic decreasing stack in terms of temperature
    • When a higher temperature is met, the required days can be calculated by currentIndex - topIndex
  • Binary Search ✅ 2023-08-03
  • Search a 2D Matrix ✅ 2023-08-03
    • Binary search on column then row, or mapping indices from 2d to 1d
  • Find Minimum In Rotated Sorted Array ✅ 2023-08-05
    • Find the pivot point between the left and right sorted array with binary search
    • nums[mid] > nums.back() if pivot is on the right side
    • nums[mid] <= nums.back() if pivot is on the left side or pivot is nums[mid]
  • Search In Rotated Sorted Array ✅ 2023-08-06
    • A good way to visualize this problem would be to draw a dotted plot, this makes differentiating the left and right sorted halves and comparing pointers easier
    • nums[mid] > nums.back() and nums[mid] <= nums.back() also works for checking which sorted halves the middle is at
    • nums[mid] >= nums[left] (in left sorted part)
      • target >= nums[left] && target < nums[mid]
        • search left
      • target < nums[left] || target > nums[mid]
        • search right
    • nums[mid] < nums[left] (in right sorted part)
      • target <= nums[right] && target > nums[mid]
        • search right
      • target > nums[right] || target < nums[mid]
        • search left

Linked List

Trees

Tries

Heap/Priority Queue

Backtracking

  • Combination Sum ✅ 2023-08-17
    • Maintain a pointer indicating that the elements at that point and after can be used as a candidate, for avoiding duplicate in the recursion tree
    • DFS through the candidates and backtrack, add to result if we reached target, return if target cannot be reached or pointer exceeds the size of candidates
  • Word Search ✅ 2023-08-17
    • Keeping track of word index to know if the path is valid
    • Mark visited path and reverting it after DFS

Graphs

Advanced Graphs

1D Dynamic Programming

  • Climbing Stairs ✅ 2023-08-08
    • Bottom-up, same as fibonacci sequence
  • House Robber ✅ 2023-08-08
    • Bottom-up, can be optimized using two variables
  • House Robber II ✅ 2023-08-09
    • Cannot rob the first and last house at the same time
    • Divide into two ranges [0, len(nums) - 1) and [1, len(nums))
  • Longest Palindromic Substring ✅ 2023-08-20
    • Checking all substrings from longest to shortest and early returning
    • Dynamically programming
    • Expanding from center
    • Manacher’s algorithm
  • Palindromic Substrings ✅ 2023-08-20
    • Check odd and even palindromes by expanding from center
  • Decode Ways ✅ 2023-08-30
    • Solving the subproblem for the number of ways the string can be decoded at index i
    • Branching the search to i + 1 and i + 2 if we decode a two-digit number
  • Coin Change ✅ 2023-08-29
    • Recursion, memoization, dynamic programming
    • Solving the subproblem for the fewest number of coins required
  • Maximum Product Subarray
  • Word Break
  • Longest Increasing Subsequence

2D Dynamic Programming

  • Unique Paths ✅ 2023-09-01
    • Maintain a m x n matrix to store the unique ways to navigate to the end at a given point
    • Iterate from the end, adding the memoized unique ways together
    • Further optimization can be done by using a dynamic programming array of only two rows, since we only need those information
  • Longest Common Subsequence

Greedy

  • Maximum Subarray ✅ 2023-08-13
    • Kadane’s Algorithm, i.e. dynamic programming by solving the maximum subarray at index i
    • The maximum subarray at index i is max(dp[i - 1] + nums[i], nums[i]), i.e. start a new subarray if we cannot obtain a larger subarray by including the current index
    • The result would be the largest value in the dp array, we could also run the algorithm in-place to obtain O(1) space complexity
  • Jump Game ✅ 2023-09-01
    • Dynamic programming from the back, memoizing whether the back can be reached at index i
    • Greedy algorithm from the back, shifting the goal forward if the previous goal can be reached, return true if the goal can be shifted to start
    • Greedy algorithm from the front, maximizing the farthest index, if farthest is less than current index, return false, otherwise return true after iteration

Intervals

  • Insert Interval ✅ 2023-08-14
    • newInterval is after intervals[i], i.e. (newInterval[0] > intervals[i][1])
      • Push intervals[i] into result
    • newInterval overlaps intervals[i], i.e. `(newInterval[0] intervals[i][1] && newInterval[1] >= intervals[i][0])
      • Update newInterval with minimum start and maximum end
      • Push newInterval into result after all merging
    • Push the remaining intervals into result
  • Merge Intervals ✅ 2023-08-14
    • Sort the intervals first, then merge if overlap, otherwise push into result
  • Non Overlapping Intervals ✅ 2023-08-14
    • Sort intervals by start
    • Maintain a prevEnd variable that greedily choose to keep the smaller end if intervals overlaps, i.e. to maximize the number of non-overlapping intervals by allowing more choices
    • If intervals does not overlap, move preEnd to the next interval
  • Meeting Rooms
  • Meeting Rooms II

Math & Geometry

  • Happy Number ✅ 2023-07-31
  • Rotate Image ✅ 2023-08-13
    • Clockwise: transpose and swap columns
    • Anti-clockwise: Transpose and swap rows
  • Spiral Matrix ✅ 2023-08-15
    • Maintain bounds in four directions, iterate until bounds overlap
    • Or extract the first element of the matrix, recursively do the same operation on the remaining matrix with negative 90 degree rotation
  • Set Matrix Zeroes ✅ 2023-08-15
    • O(1) space can be achieved by using first row and first column plus one extra variable for flagging
    • Note that the iteration step must start from the bottom-right hand corner to avoid crashing with flags

Bit Manipulation

  • Number of 1 Bits ✅ 2023-08-07
    • n = n & (n - 1) to remove one digit of 1 at a time, so we only have to loop as many times as there are 1s.
  • Counting Bits ✅ 2023-08-18
    • Maintaining offset for dynamic programming, which corresponds to the power of 2
    • Number of 1’s can be deduced from the previous significant integers, i.e. dp[i] = dp[i - offset] + 1
  • Reverse Bits ✅ 2023-08-18
  • Missing Number ✅ 2023-08-08
    • XOR is commutative and associative (order doesn’t matter)
    • XOR a number with itself would result in 0 (e.g. 10 ^ 10 = 00)
    • XOR a number with 0 would result in itself (e.g. 10 ^ 00 = 10)
    • We XOR all the numbers in the range [0, nums.size()] twice except missing_number, what is left is 0 ^ missing_number since everything else cancels to 0, and 0 ^ missing_number is the missing_number
  • Sum of Two Integers ✅ 2023-09-01
    • XOR to figure out the sum without carry, i.e. a ^ b
    • AND to figure out the carry bits, i.e. (a & b) << 1
    • Loop until there is no carry bits