Resources
Throughout the semester, I will fill this webpage with useful resources. Most (if not all) of these resources will be freely available online.
In-Class LeetCode
In this section, I will post the LeetCode problems we have tackled in class, as well as the code we wrote to solve the problems. This section will continue to grow throughout the semester. Note that it is posted in reverse chronological order (most recent problems are posted first).
Minimum Cost to Cut a Stick
Link; (Dynamic Programming, Nov. 25, 2025)
Top-down DP (Memoization)
class Solution {
vector<vector<int>> dp;
public:
int computeCost(int i, int j, int start, int end, vector<int>& cuts) {
if(i > j) return 0;
if(dp[i][j] != 0) return dp[i][j];
int minCost = INT_MAX;
for(int k = i; k <= j; k++) {
int left = computeCost(i, k-1, start, cuts[k], cuts);
int right = computeCost(k+1, j, cuts[k], end, cuts);
int my_cost = end - start;
minCost = min(minCost, left+right+my_cost);
}
dp[i][j] = minCost;
return dp[i][j];
}
int minCost(int n, vector<int>& cuts) {
int s = cuts.size();
sort(cuts.begin(), cuts.end());
dp = vector<vector<int>>(s, vector<int>(s));
return computeCost(0, s-1, 0, n, cuts);
}
};
Bottom-up DP (Tabulation)
class Solution {
vector<vector<int>> dp;
public:
int minCost(int n, vector<int>& cuts) {
int s = cuts.size();
sort(cuts.begin(), cuts.end());
dp = vector<vector<int>>(s, vector<int>(s));
// tabulation
for(int i = s-1; i>=0; --i) {
for(int j = i; j < s; ++j) {
int minCost = INT_MAX;
int start = 0;
if(i > 0) start = cuts[i-1];
int end = n;
if(j < s-1) end = cuts[j+1];
for(int k = i; k <= j; ++k) {
int left = 0;
int right = 0;
if(k > i) left = dp[i][k-1];
if(k < j) right = dp[k+1][j];
minCost = min(minCost, left+right+(end-start));
}
dp[i][j] = minCost;
}
}
return dp[0][s-1];
}
};
Binary Tree Maximum Path Sum
Link; (Dynamic Programming, Nov. 20, 2025)
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int global_max = numeric_limits<int>::min();
int findMax(TreeNode* root) {
if(root == nullptr) return 0;
int left = max(0, findMax(root->left));
int right = max(0, findMax(root->right));
global_max = max(global_max, root->val + left + right);
return root->val + max(left, right);
}
int maxPathSum(TreeNode* root) {
findMax(root);
return global_max;
}
};
Dungeon Game
Link; (Dynamic Programming, Nov. 18, 2025)
class Solution {
public:
int calculateMinimumHP(vector<vector<int>>& dungeon) {
int m = dungeon.size();
int n = dungeon[0].size();
vector<vector<int>> dp(m+1, vector<int>(n+1, INT_MAX));
dp[m][n-1] = 1;
dp[m-1][n] = 1;
for(int i = m-1; i >= 0; --i) {
for(int j = n-1; j >= 0; --j) {
int val = min(dp[i+1][j], dp[i][j+1]) - dungeon[i][j];
dp[i][j] = (val <= 0) ? 1 : val;
// if(val <= 0) {
// dp[i][j] = 1;
// }
// else {
// dp[i][j] = val;
// }
}
}
return dp[0][0];
}
};
Binary Tree Cameras
Link; (Dynamic Programming + Trees, Nov. 13, 2025)
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
vector<vector<int>> memoization;
int dp(TreeNode* root, int state) {
if(root == nullptr) {
return state==2;
}
else if(memoization[root->val][state]!= -1) {
return memoization[root->val][state];
}
else {
int cur_val = INT_MAX;
switch(state) {
case 2: {
cur_val = min(cur_val, 1+dp(root->left,1) + dp(root->right,1));
break;
}
case 1: {
cur_val = min(cur_val, dp(root->left,0) + dp(root->right,0));
cur_val = min(cur_val, 1+dp(root->left,1)+dp(root->right,1));
break;
}
default: { // case 0
cur_val = min(cur_val,1+dp(root->left,1)+dp(root->right,1));
cur_val = min(cur_val, dp(root->left,2)+dp(root->right,0));
cur_val = min(cur_val, dp(root->left,0)+dp(root->right,2));
break;
}
}
memoization[root->val][state] = cur_val;
return memoization[root->val][state];
}
}
void dfs(int& n, TreeNode* root) {
if(root == nullptr) return;
root->val=n++;
dfs(n,root->left);
dfs(n, root->right);
}
int minCameraCover(TreeNode* root) {
if(root == nullptr) return 0;
int n = 0;
dfs(n, root);
memoization = vector<vector<int>>(n);
for(int i = 0; i < n; ++i) {
memoization[i] = {-1, -1, -1};
}
return dp(root,0);
}
};
Binary Trees With Factors
Link; (Dynamic Programming + Trees, Nov. 13, 2025)
class Solution {
public:
int numFactoredBinaryTrees(vector<int>& arr) {
long result = 0;
long mod = pow(10,9) + 7;
unordered_map<int, long> tablu;
sort(arr.begin(), arr.end()); //arr[i], arr[j] for j < i
for(int i = 0; i < arr.size(); ++i) {
tablu[arr[i]] = 1;
for(int j = 0; j < i; ++j) {
// [2, 4, 8, 16]
if(arr[i] % arr[j] == 0) {
tablu[arr[i]] = (tablu[arr[i]] + tablu[arr[j]]*tablu[arr[i]/arr[j]]) % mod;
}
}
result = (result + tablu[arr[i]]) % mod;
}
return result;
}
};
Fibonacci Number
Link; (Dynamic Programming, Nov. 11, 2025)
class Solution {
public:
int fib_recurse(int n) {
// bad exp time!
if(n == 0 || n == 1) {
return n;
}
else return fib_recurse(n-1) + fib_recurse(n-2);
}
int fib_memo_help(vector<int>& table, int n) {
if(n == 0) {
return 0;
}
if(table[n] > 0) {
return table[n];
}
table[n] = fib_memo_help(table, n-1) + fib_memo_help(table, n-2);
return table[n];
}
int fib_top_down_memo(int n) {
vector<int> table(n+1,0);
table[1] = 1;
return fib_memo_help(table,n);
}
int fib_bottom_up(int n) {
if(n == 0 || n == 1) {
return n;
}
int val0 = 0;
int val1 = 1;
for(int i = 2; i < n+1; ++i) {
int tmp = val1;
val1 = val1+val0;
val0 = tmp;
}
return val1;
}
int fib(int n) {
return fib_bottom_up(n);
}
};
Serialize and Deserialize Binary Tree
Link (Trees, Nov. 6, 2025)
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Codec {
public:
const string null = "null";
// Encodes a tree to a single string.
string val_to_str(int val) {
int shifted_val = 1000+val;
string out = to_string(shifted_val);
while(out.size() < 4) {
out = "0" + out;
}
return out;
}
int str_to_val(string str) {
// assumes str is of length 4
int val = stoi(str);
val = val-1000;
return val;
}
string serialize(TreeNode* root) {
if(root == nullptr) return null;
string out = "";
// construct pre-order DFS string
out += val_to_str(root->val);
out += serialize(root->left);
out += serialize(root->right);
return out;
}
TreeNode* deserialize_help(string& data, unsigned int& start_pos) {
string curr = data.substr(start_pos,4);
//data.erase(0,4);
if(curr == null) return nullptr;
TreeNode* root = new TreeNode(str_to_val(curr));
start_pos += 4;
root->left = deserialize_help(data, start_pos);
start_pos +=4;
root->right = deserialize_help(data, start_pos);
return root;
}
// Decodes your encoded data to tree.
TreeNode* deserialize(string data) {
//string data_copy(data);
unsigned int start = 0;
return deserialize_help(data, start);
}
};
// Your Codec object will be instantiated and called as such:
// Codec ser, deser;
// TreeNode* ans = deser.deserialize(ser.serialize(root));
Tree of Coprimes
Link (Trees, Nov. 4, 2025)
class Solution {
public:
vector<vector<int>> tree;
unordered_map<int, vector<int>> coprimes;
unordered_map<int, vector<pair<int, int>>> path;
void DFS(int curr_id, int curr_depth, int parent_id, vector<int>& nums, vector<int>& ans) {
// check if nums[curr_id] is coprime to anything in the current path
int max_depth = -1;
for(int val: coprimes[nums[curr_id]]) {
vector<pair<int,int>>& ancestors = path[val];
if(!ancestors.empty() && ancestors.back().second > max_depth) {
max_depth = ancestors.back().second;
ans[curr_id] = ancestors.back().first;
}
}
path[nums[curr_id]].push_back({curr_id, curr_depth});
for(int child_id : tree[curr_id]) {
if(child_id != parent_id) {
DFS(child_id, curr_depth+1, curr_id, nums, ans);
}
}
path[nums[curr_id]].pop_back();
}
vector<int> getCoprimes(vector<int>& nums, vector<vector<int>>& edges) {
int n = nums.size();
vector<int> ans = vector<int>(n, -1);
tree = vector<vector<int>>(n);
// Build the tree
for(const auto edge: edges) {
tree[edge[0]].push_back(edge[1]);
tree[edge[1]].push_back(edge[0]);
}
unordered_set<int> set(nums.begin(), nums.end());
for(int n1 : set) {
for(int n2 : set) {
if(gcd(n1, n2) == 1) coprimes[n1].push_back(n2);
}
}
DFS(0, 0, -1, nums, ans);
return ans;
}
};
Binary Tree Level Order Traversal
Link (Trees, Oct. 30, 2025)
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
if(root == nullptr) return {};
queue<TreeNode*> bfs_queue;
bfs_queue.push(root);
vector<vector<int>> output {};
while(!bfs_queue.empty()) {
int num_in_lvl = bfs_queue.size();
vector<int> curr_lvl_order {};
while(num_in_lvl > 0) {
TreeNode* curr = bfs_queue.front();
bfs_queue.pop();
--num_in_lvl;
curr_lvl_order.push_back(curr->val);
if(curr->left != nullptr) {
bfs_queue.push(curr->left);
}
if(curr->right != nullptr) {
bfs_queue.push(curr->right);
}
}
output.push_back(curr_lvl_order);
}
return output;
}
};
Construct Binary Tree from Inorder and Postorder Traversal
Link (Trees, Oct. 16, 2025)
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
// we'll use a hashmap so we don't have to search through the inorder vector every time!
unordered_map<int, int> hash_map;
// int_end is inclusive;
TreeNode* buildSubtree(
vector<int>& inorder,
vector<int>& postorder,
int in_start,
int in_end,
int& post_root_index
) {
if(in_start > in_end) return nullptr;
TreeNode* root = new TreeNode(postorder[post_root_index--]);
int inorder_root_index = hash_map[root->val];
int right_size = in_end - inorder_root_index;
root->right = buildSubtree(inorder, postorder, inorder_root_index+1, in_end, post_root_index);
root->left = buildSubtree(inorder, postorder, in_start, inorder_root_index-1, post_root_index);
return root;
}
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
for(int i = 0; i < inorder.size(); ++i) {
hash_map[inorder[i]] = i;
}
int n = inorder.size();
int post_root_index = n-1;
return buildSubtree(inorder, postorder, 0, n-1, post_root_index);
}
};
Minimum Height Trees
Link (Trees, Oct. 14, 2025)
class Solution {
public:
vector<int> findMinHeightTrees(int n, vector<vector<int>>& edges) {
if(n == 1) return vector<int>{0};
vector<vector<int>> tree(n);
vector<int> degree(n, 0);
for(vector<int> edge: edges) {
tree[edge[0]].push_back(edge[1]);
tree[edge[1]].push_back(edge[0]);
++degree[edge[0]];
++degree[edge[1]];
}
vector<int> output;
queue<int> deg_1_queue;
for(int i = 0; i < n; ++i) {
if(degree[i] == 1) deg_1_queue.push(i);
}
while(!deg_1_queue.empty()) {
int queue_size = deg_1_queue.size();
output.clear();
while(queue_size) {
int curr = deg_1_queue.front();
deg_1_queue.pop();
output.push_back(curr);
for(int i = 0; i < tree[curr].size(); ++i) {
--degree[tree[curr][i]];
if(degree[tree[curr][i]]==1) {
deg_1_queue.push(tree[curr][i]);
}
}
--queue_size;
}
}
return output;
}
};
Shortest Path with Alternating Colors
Link (Graphs, Oct. 14, 2025) DFS approach.
class Solution {
public:
vector<vector<int>> red_graph;
vector<vector<int>> blue_graph;
vector<int> shortest_red;
vector<int> shortest_blue;
void calcShortest(int node, int path_len, char edge_color) {
switch(edge_color) {
case 'b':
if(shortest_blue[node] == -1 || path_len < shortest_blue[node]) {
shortest_blue[node] = path_len;
for(int i = 0; i < red_graph[node].size(); ++i) {
calcShortest(red_graph[node][i], path_len+1, 'r');
}
}
break;
case 'r':
if(shortest_red[node] == -1 || path_len < shortest_red[node]) {
shortest_red[node] = path_len;
for(int i = 0; i < blue_graph[node].size(); ++i) {
calcShortest(blue_graph[node][i], path_len+1, 'b');
}
}
break;
default:
throw std::invalid_argument( "received incorrect edge color" );
}
}
vector<int> shortestAlternatingPaths(int n, vector<vector<int>>& redEdges, vector<vector<int>>& blueEdges) {
red_graph = vector<vector<int>>(n);
blue_graph = vector<vector<int>>(n);
shortest_red = vector<int>(n);
shortest_blue = vector<int>(n);
// these will track the shortest paths from node 0 to node i when entering
// node i from the respective color
shortest_red[0] = 0;
shortest_blue[0] = 0;
// init all path lengths
for(int i = 1; i < n; ++i) {
shortest_red[i] = -1;
shortest_blue[i] = -1;
}
// construct the graphs
for(vector<int> redge: redEdges) {
red_graph[redge[0]].push_back(redge[1]);
}
for(vector<int> bedge: blueEdges) {
blue_graph[bedge[0]].push_back(bedge[1]);
}
for(int i = 0; i < red_graph[0].size(); ++i) {
calcShortest(red_graph[0][i], 1, 'r');
}
for(int i = 0; i < blue_graph[0].size(); ++i) {
calcShortest(blue_graph[0][i], 1, 'b');
}
vector<int> output(n);
output[0] = 0;
for(int i = 1; i < n; ++i) {
if(shortest_red[i] == -1 && shortest_blue[i] == -1) {
output[i] = -1;
}
else if(shortest_red[i] == -1) {
output[i] = shortest_blue[i];
}
else if(shortest_blue[i] == -1) {
output[i] = shortest_red[i];
}
else {
output[i] = (shortest_red[i] <= shortest_blue[i]) ? shortest_red[i] : shortest_blue[i];
}
}
return output;
}
};
BFS approach.
class Solution {
public:
vector<vector<int>> red_graph;
vector<vector<int>> blue_graph;
vector<int> shortest_red;
vector<int> shortest_blue;
vector<int> shortestAlternatingPaths(int n, vector<vector<int>>& redEdges, vector<vector<int>>& blueEdges) {
red_graph = vector<vector<int>>(n);
blue_graph = vector<vector<int>>(n);
shortest_red = vector<int>(n);
shortest_blue = vector<int>(n);
// these will track the shortest paths from node 0 to node i when entering
// node i from the respective color
shortest_red[0] = 0;
shortest_blue[0] = 0;
// init all path lengths
for(int i = 1; i < n; ++i) {
shortest_red[i] = -1;
shortest_blue[i] = -1;
}
// construct the graphs
for(vector<int> &redge: redEdges) {
red_graph[redge[0]].push_back(redge[1]);
}
for(vector<int> &bedge: blueEdges) {
blue_graph[bedge[0]].push_back(bedge[1]);
}
// BFS approach
queue<vector<int>> bfs_queue;
// 0 = red; 1 = blue
bfs_queue.push({0, 0});
bfs_queue.push({0, 1});
while(!bfs_queue.empty()) {
vector<int> curr_list = bfs_queue.front();
bfs_queue.pop();
int curr_node = curr_list[0];
int curr_color = curr_list[1];
// if coming from red, search all blue
if(curr_color == 0) {
int distance = shortest_red[curr_node];
for(int neigh: blue_graph[curr_node]) {
if(shortest_blue[neigh] == -1 || distance+1 < shortest_blue[neigh]) {
shortest_blue[neigh] = distance + 1;
bfs_queue.push({neigh, 1});
}
}
}
else { // if coming from blue, search all red
int distance = shortest_blue[curr_node];
for(int neigh: red_graph[curr_node]) {
if(shortest_red[neigh] == -1 || distance+1 < shortest_red[neigh]) {
shortest_red[neigh] = distance + 1;
bfs_queue.push({neigh, 0});
}
}
}
}
vector<int> output(n);
output[0] = 0;
for(int i = 1; i < n; ++i) {
if(shortest_red[i] == -1 && shortest_blue[i] == -1) {
output[i] = -1;
}
else if(shortest_red[i] == -1) {
output[i] = shortest_blue[i];
}
else if(shortest_blue[i] == -1) {
output[i] = shortest_red[i];
}
else {
output[i] = (shortest_red[i] <= shortest_blue[i]) ? shortest_red[i] : shortest_blue[i];
}
}
return output;
}
};
Cheapest Flights within K Stops
Link (Graphs, Oct. 9, 2025)
const int infinity = std::numeric_limits<int>::max();
struct Node {
int id;
int price;
int stop_num;
vector<Node> neighbors;
bool operator> (const Node&) const;
bool operator>=(const Node&) const;
bool operator==(const Node&) const;
bool operator< (const Node&) const;
bool operator<=(const Node&) const;
bool operator!=(const Node&) const;
};
bool Node::operator> (const Node& node) const {return price > node.price; }
bool Node::operator>=(const Node& node) const {return price >= node.price; }
bool Node::operator==(const Node& node) const {return price == node.price; }
bool Node::operator< (const Node& node) const {return price < node.price; }
bool Node::operator<=(const Node& node) const {return price <= node.price; }
bool Node::operator!=(const Node& node) const{return price != node.price; }
class Solution {
public:
int findCheapestPrice(int n, vector<vector<int>>& flights, int src, int dst, int k) {
vector<Node> graph;
for(int i = 0; i < n; ++i) {
graph.push_back(Node(i, infinity, infinity, {}));
}
for(vector<int> edge: flights) {
graph[edge[0]].neighbors.push_back(Node(edge[1], edge[2], 0, {}));
}
priority_queue<Node, std::vector<Node>, std::greater<Node>> min_queue;
min_queue.push(Node(src, 0, 0, {}));
while(!min_queue.empty()) {
Node curr = min_queue.top();
min_queue.pop();
if(curr.id == dst) return curr.price;
if(curr.stop_num > k || curr.stop_num > graph[curr.id].stop_num) continue;
graph[curr.id].stop_num = curr.stop_num;
for(Node neigh: graph[curr.id].neighbors) {
min_queue.push(Node(neigh.id, curr.price+neigh.price, curr.stop_num+1));
}
}
return -1;
}
};
Alternative, more elegant solution from LeetCode contributor.
const int infinity = std::numeric_limits<int>::max();
class Solution {
public:
int findCheapestPrice(int n, vector<vector<int>>& flights, int src, int dst, int k) {
vector<vector<vector<int>>> graph(n);
for(vector<int> edge: flights) {
// graph[i] is a vector<vector<int>>
// graph[i][j] is a vector<int> of the form: { to_id, price }
graph[edge[0]].push_back({edge[1], edge[2]});
}
// track current number of stops of each node
vector<int> num_stops(n, infinity);
// nodes are stored in the form: { price, id, num_stops}
priority_queue<array<int,3>, vector<array<int,3>>, greater<>> min_queue;
min_queue.push({0, src, 0});
while(!min_queue.empty()) {
auto [price, id, stops] = min_queue.top();
min_queue.pop();
if(id == dst) return price;
if(stops > k || stops > num_stops[id]) continue;
num_stops[id] = stops;
for(int i = 0; i < graph[id].size(); ++i) {
min_queue.push({price + graph[id][i][1], graph[id][i][0], stops+1});
}
}
return -1;
}
};
Course Schedule II
Link (Graphs, Oct. 2, 2025)
Note that this also solves Course Schedule.
class Solution {
public:
vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) {
// First, make graph via adj list!
vector<vector<int>> graph(numCourses);
vector<int> visited(numCourses);
// Our graph representation will be a predecessor representation. That is,
// graph[i] is a list / hashmap of all the nodes j such that (j,i) is an edge.
// In other words, graph[i] contains all courses j that are a prereq for i.
for(vector<int> prereq: prerequisites) {
graph[ prereq[0] ].push_back( prereq[1] );
}
// Now, we need to topologically sort the graph. You can do this via BFS or DFS.
// vector representing the final ordering
vector<int> order {};
// BFS approach
queue<int> bfs_queue {};
// we need to find all nodes with no predecessors so we can start our sorting algorithm
for(int i = 0; i < numCourses; ++i) {
if(graph[i].empty()) {
bfs_queue.push(i);
visited[i] = 1;
}
}
//if(bfs_queue.empty()) return order; // return empty list!
while(!bfs_queue.empty()) {
int curr = bfs_queue.front();
bfs_queue.pop();
order.push_back(curr);
for(int i = 0; i < numCourses; ++i) {
if(i == curr) continue;
for(int j = 0; j < graph[i].size(); ++j) {
if(graph[i][j] == curr) {
graph[i].erase(graph[i].begin()+j);
break;
}
}
if(graph[i].empty() && !visited[i]) {
bfs_queue.push(i);
visited[i] = 1;
}
}
}
if(order.size() < numCourses) return vector<int>();
return order;
}
};
Number of Islands
Link (Graphs, Sept. 30 and Oct. 2, 2025)
DFS Approach.
class Solution {
public:
// Return the index of pair (row, col) in row-major order
int pair_to_index(const int row, const int col, const int num_cols) {
return (num_cols*row + col);
}
void recursive_dfs(vector<vector<char>>& grid, int num_rows, int num_cols, int i, int j, vector<bool>& visited) {
// visit the current node
visited[pair_to_index(i,j, num_cols)] = true;
// visit in clockwise order starting from the top
// visit north
if(i > 0 && grid[i-1][j] == '1' && !visited[pair_to_index(i-1,j, num_cols)]) {
recursive_dfs(grid, num_rows, num_cols, i-1, j, visited);
}
// visit east
if(j < num_cols-1 && grid[i][j+1] == '1' && !visited[pair_to_index(i,j+1, num_cols)]) {
recursive_dfs(grid, num_rows, num_cols, i, j+1, visited);
}
// visit south
if(i < num_rows-1 && grid[i+1][j] == '1' && !visited[pair_to_index(i+1,j, num_cols)]) {
recursive_dfs(grid, num_rows, num_cols, i+1, j, visited);
}
// visit west
if(j > 0 && grid[i][j-1] == '1' && !visited[pair_to_index(i,j-1, num_cols)]) {
recursive_dfs(grid, num_rows, num_cols, i, j-1, visited);
}
return;
}
int numIslands(vector<vector<char>>& grid) {
int m = grid.size();
int n = grid[0].size();
int num_islands = 0;
int total_size = m * n;
vector<bool> visited(total_size);
for(int i = 0; i < m; i++) {
for(int j = 0; j < n; j++) {
if(grid[i][j] == '1' && !visited[pair_to_index(i, j, n)]) {
// recursive DFS
recursive_dfs(grid, m, n, i, j, visited);
++num_islands;
}
}
}
return num_islands;
}
};
BFS Approach.
class Solution {
public:
// Return the index of pair (row, col) in row-major order
int pair_to_index(const int row, const int col, const int num_cols) {
return (num_cols*row + col);
}
int index_to_row(const int index, const int num_cols) {
return index / num_cols;
}
int index_to_col(const int index, const int num_cols) {
return index % num_cols;
}
int numIslands(vector<vector<char>>& grid) {
int m = grid.size();
int n = grid[0].size();
int num_islands = 0;
int total_size = m * n;
vector<bool> visited(total_size);
queue<int> bfs_queue;
for(int i = 0; i < m; i++) {
for(int j = 0; j < n; j++) {
if(grid[i][j] == '1' && !visited[pair_to_index(i, j, n)]) {
visited[pair_to_index(i,j,n)] = true;
// Loop BFS
bfs_queue.push(pair_to_index(i,j,n));
while(!bfs_queue.empty()) {
int index = bfs_queue.front();
bfs_queue.pop();
int row = index_to_row(index, n);
int col = index_to_col(index, n);
// visit the node
visited[index] = true;
// do BFS, clockwise starting north
// visit north
if(row > 0 && grid[row-1][col] == '1' && !visited[pair_to_index(row-1, col, n)]) {
visited[pair_to_index(row-1,col,n)] = true;
bfs_queue.push(pair_to_index(row-1, col, n));
}
// visit east
if(col < n-1 && grid[row][col+1] == '1' && !visited[pair_to_index(row,col+1, n)]) {
visited[pair_to_index(row,col+1,n)] = true;
bfs_queue.push(pair_to_index(row, col+1, n));
}
// visit south
if(row < m-1 && grid[row+1][col] == '1' && !visited[pair_to_index(row+1,col, n)]) {
visited[pair_to_index(row+1,col,n)] = true;
bfs_queue.push(pair_to_index(row+1, col, n));
}
// visit west
if(col > 0 && grid[row][col-1] == '1' && !visited[pair_to_index(row,col-1, n)]) {
visited[pair_to_index(row,col-1,n)] = true;
bfs_queue.push(pair_to_index(row, col-1, n));
}
}
++num_islands;
}
}
}
return num_islands;
}
};
Clone Graph
Link (Graphs, Sept. 25, 2025)
/*
// Definition for a Node.
class Node {
public:
int val;
vector<Node*> neighbors;
Node() {
val = 0;
neighbors = vector<Node*>();
}
Node(int _val) {
val = _val;
neighbors = vector<Node*>();
}
Node(int _val, vector<Node*> _neighbors) {
val = _val;
neighbors = _neighbors;
}
};
*/
class Solution {
public:
Node* cloneGraph(Node* node) {
queue<Node*> bfs_queue {};
unordered_map<int, Node*> cloned_nodes {};
if(node == nullptr) {
return nullptr;
}
Node* clone_start = new Node(node->val);
cloned_nodes[clone_start->val] = clone_start;
bfs_queue.push(node);
while(!bfs_queue.empty()) {
Node* curr = bfs_queue.front();
bfs_queue.pop();
for(Node* neigh: curr->neighbors) {
cout << neigh->val << ", ";
if(!cloned_nodes[neigh->val]) {
cloned_nodes[neigh->val] = new Node(neigh->val);
bfs_queue.push(neigh);
}
cloned_nodes[curr->val]->neighbors.push_back(cloned_nodes[neigh->val]);
}
}
return clone_start;
}
};
Group Anagrams
Link (Hashing, Sept. 18, 2025)
class Solution {
public:
vector<vector<string>> groupAnagrams(vector<string>& strs) {
// step 1: given a string s, make new string s' where s' is char's of s sorted
// example:
// "eat" -> "aet"
// step 2: sorted s' is your key, hash table is a table of arrays
// unordered_map<string, string[]> H;
// H[s'].append(s);
// example: "eat" -> "aet"
// H["aet"].push("eat");
// issue: what if hash("aet") = hash("efg")
unordered_map<string, vector<string>> map;
for(string str : strs) {
string strcpy = str;
sort(strcpy.begin(),strcpy.end());
map[strcpy].push_back(str);
}
vector<vector<string>> out;
for(auto k: map) {
out.push_back(k.second);
}
return out;
}
};
First Missing Positive
Link (Hashing, Sept. 18, 2025)
class Solution {
public:
int firstMissingPositive(vector<int>& nums) {
int i;
for(i = 0; i < nums.size(); i++) {
if(nums[i] <=0 or nums[i] >= nums.size()+1) nums[i] = nums.size()+1;
}
for(i=0; i < nums.size(); i++) {
if(abs(nums[i]) <= nums.size()) nums[abs(nums[i])-1] = -1*abs(nums[abs(nums[i])-1]);
}
for(i=0; i < nums.size(); i++) {
if(nums[i] > 0) {
return i+1;
}
}
return nums.size()+1;
}
};
Longest Substring Without Repeating Characters
Link (Hashing, Sept. 16, 2025)
class Solution {
public:
int lengthOfLongestSubstring(string s) {
short int seen_char[256] {};
int max_length = 0;
short int left = 0;
short int diff = 0;
for(short int right = 0; right < s.size(); ++right) {
++diff;
if(!seen_char[s[right]]) {
++seen_char[s[right]];
max_length = (diff > max_length) ? diff : max_length;
}
else {
while(seen_char[s[right]]) {
--seen_char[s[left]];
++left;
--diff;
}
++seen_char[s[right]];
}
}
return max_length;
}
};
Longest Substring Without Repeating Characters
Link (Hashing, Sept. 11, 2025)
#include <unordered_set>
#include <math.h>
class Solution {
public:
int lengthOfLongestSubstring(string s) {
int max_len = 0;
unordered_set<char> char_set;
auto left = s.begin();
for(auto right = s.begin(); right != s.end(); right++) {
if(char_set.count(*right) == 0) {
char_set.insert(*right);
max_len = max(max_len, static_cast<int>(right-left+1));
}
else {
while(char_set.count(*right)) {
char_set.erase(*left);
left++;
}
char_set.insert(*right);
}
}
return max_len;
}
};
Two Sum
Link (Hashing, Sept. 11, 2025)
#include <unordered_map>
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
vector<int> indices{-1, -1};
unordered_map<int,int> hashmap;
for(int i = 0; i < nums.size(); i++) {
hashmap[nums[i]] = i;
}
for(int i = 0; i < nums.size(); i++) {
int y = target - nums[i];
if(hashmap[y] && hashmap[y] != i) {
indices[0] = i;
indices[1] = hashmap[y];
break;
}
}
return indices;
}
};