--- title: 'Bloomberg' tags: LeetCode --- ## Array ### 41. First Missing Positive ```cpp class Solution { public: int firstMissingPositive(vector<int>& nums) { const int n = nums.size(); // Correct slot: // nums[i] = i + 1 // nums[i] - 1 = i // nums[nums[i] - 1] = nums[i] for (int i = 0; i < n; ++i) while (nums[i] > 0 && nums[i] <= n && nums[i] != nums[nums[i] - 1]) swap(nums[i], nums[nums[i] - 1]); for (int i = 0; i < n; ++i) if (nums[i] != i + 1) return i + 1; return n + 1; } }; ``` ## Stack ### 394. Decode String ```cpp class Solution { public: string decodeString(string s) { stack<pair<string, int>> stack; string currStr; int currNum = 0; for (const char c : s) { if (isdigit(c)) { currNum = currNum * 10 + (c - '0'); } else { if (c == '[') { stack.emplace(currStr, currNum); currStr = ""; currNum = 0; } else if (c == ']') { const auto [prevStr, n] = stack.top(); stack.pop(); currStr = prevStr + getRepeatedStr(currStr, n); } else { currStr += c; } } } return currStr; } private: string getRepeatedStr(const string& str, int n) { string s; while (n--) { s += str; } return s; } }; ``` ### 445. Add Two Numbers II ```cpp class Solution { public: ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) { int carry = 0; stack<ListNode*> stack1; stack<ListNode*> stack2; while (l1) { stack1.push(l1); l1 = l1->next; } // [7, 2, 4, 3] while (l2) { stack2.push(l2); l2 = l2->next; } // [5, 6, 4] ListNode* head = nullptr; while (carry || !stack1.empty() || !stack2.empty()) { if (!stack1.empty()) { carry += stack1.top()->val; stack1.pop(); } if (!stack2.empty()) { carry += stack2.top()->val; stack2.pop(); } ListNode* node = new ListNode(carry % 10); node->next = head; head = node; carry /= 10; } return head; } }; ``` ### 1249. Minimum Remove to Make Valid Parentheses ```cpp class Solution { public: string minRemoveToMakeValid(string s) { stack<int> stack; // unpaired '(' indicies for (int i = 0; i < s.length(); ++i) if (s[i] == '(') { stack.push(i); // record unpaired '(' index } else if (s[i] == ')') { if (stack.empty()) s[i] = '*'; // mark unpaired ')' as '*' else stack.pop(); // find a pair! } // mark unpaired '(' as '*' while (!stack.empty()) s[stack.top()] = '*', stack.pop(); s.erase(remove(begin(s), end(s), '*'), end(s)); return s; } }; ``` ### 1209. Remove All Adjacent Duplicates in String II ```cpp class Solution { public: string removeDuplicates(string s, int k) { string ans; vector<pair<char, int>> stack; for (const char c : s) { if (stack.empty() || stack.back().first != c) { stack.emplace_back(c, 1); } else if (++stack.back().second == k) { stack.pop_back(); } } for (const auto& [c, count] : stack) ans.append(count, c); return ans; } }; ``` ## Linked List ### 1244. Design A Leaderboard ```cpp class Leaderboard { public: void addScore(int playerId, int score) { idToScore[playerId] += score; } int top(int K) { int ans = 0; priority_queue<int, vector<int>, greater<>> pq; for (const auto& [id, score] : idToScore) { pq.push(score); if (pq.size() > K) pq.pop(); } while (!pq.empty()) ans += pq.top(), pq.pop(); return ans; } void reset(int playerId) { idToScore.erase(playerId); } private: unordered_map<int, int> idToScore; }; ``` ### 1472. Design Browser History #### Approach 1: Array ```cpp class BrowserHistory { public: BrowserHistory(string homepage) { visit(homepage); } void visit(string url) { if (++index < urls.size()) { urls[index] = url; } else { urls.push_back(url); } lastIndex = index; } string back(int steps) { index = max(0, index - steps); return urls[index]; } string forward(int steps) { index = min(lastIndex, index + steps); return urls[index]; } private: vector<string> urls; int index = -1; int lastIndex = -1; }; ``` #### Approach 2: Stack ```cpp class BrowserHistory { public: BrowserHistory(string homepage) { visit(homepage); } void visit(string url) { history.push(url); future = stack<string>(); } string back(int steps) { while (steps-- > 0 && history.size() > 1) future.push(history.top()), history.pop(); return history.top(); } string forward(int steps) { while (steps-- > 0 && !future.empty()) history.push(future.top()), future.pop(); return history.top(); } private: stack<string> history; stack<string> future; }; ``` #### Approach 3: Doubly-Linked List ```cpp struct Node { Node(const string& url) : url(url) {} Node* prev = nullptr; Node* next = nullptr; const string url; }; class BrowserHistory { public: BrowserHistory(string homepage) { curr = new Node(homepage); } void visit(string url) { curr->next = new Node(url); curr->next->prev = curr; curr = curr->next; } string back(int steps) { while (curr->prev && steps-- > 0) curr = curr->prev; return curr->url; } string forward(int steps) { while (curr->next && steps-- > 0) curr = curr->next; return curr->url; } private: Node* curr = nullptr; }; ``` ## OOP ### 1396. Design Underground System ```cpp struct CheckIn { string stationName; int time; }; struct CheckOut { int numTrips; int totalTime; }; class UndergroundSystem { public: void checkIn(int id, string stationName, int t) { checkIns[id] = {stationName, t}; } void checkOut(int id, string stationName, int t) { const auto [startStation, startTime] = checkIns[id]; checkIns.erase(id); const string& route = startStation + "->" + stationName; ++checkOuts[route].numTrips; checkOuts[route].totalTime += t - startTime; } double getAverageTime(string startStation, string endStation) { const auto& [numTrips, totalTime] = checkOuts[startStation + "->" + endStation]; return totalTime / (double)numTrips; } private: unordered_map<int, CheckIn> checkIns; // {id: (stationName, time)} unordered_map<string, CheckOut> checkOuts; // {route: (numTrips, totalTime)} }; ``` ## Tree ### 103. Binary Tree Zigzag Level Order Traversal #### Approach 1: Deque ```cpp class Solution { public: vector<vector<int>> zigzagLevelOrder(TreeNode* root) { if (!root) return {}; vector<vector<int>> ans; deque<TreeNode*> q{{root}}; bool isLeftToRight = true; while (!q.empty()) { vector<int> currLevel; for (int size = q.size(); size > 0; --size) if (isLeftToRight) { TreeNode* node = q.front(); q.pop_front(); currLevel.push_back(node->val); if (node->left) q.push_back(node->left); if (node->right) q.push_back(node->right); } else { TreeNode* node = q.back(); q.pop_back(); currLevel.push_back(node->val); if (node->right) q.push_front(node->right); if (node->left) q.push_front(node->left); } ans.push_back(currLevel); isLeftToRight = !isLeftToRight; } return ans; } }; ``` #### Approach 2: Queue ```cpp class Solution { public: vector<vector<int>> zigzagLevelOrder(TreeNode* root) { if (!root) return {}; vector<vector<int>> ans; queue<TreeNode*> q{{root}}; bool isLeftToRight = true; while (!q.empty()) { const int size = q.size(); vector<int> currLevel(size); for (int i = 0; i < size; ++i) { TreeNode* node = q.front(); q.pop(); const int index = isLeftToRight ? i : size - i - 1; currLevel[index] = node->val; if (node->left) q.push(node->left); if (node->right) q.push(node->right); } ans.push_back(node); isLeftToRight = !isLeftToRight; } return ans; } }; ``` #### Approach 3: DFS ### 501. Find Mode in Binary Search Tree ```cpp class Solution { public: vector<int> findMode(TreeNode* root) { vector<int> ans; int count = 0; int maxCount = 0; inorder(root, count, maxCount, ans); return ans; } private: TreeNode* pred = nullptr; void inorder(TreeNode* root, int& count, int& maxCount, vector<int>& ans) { if (!root) return; inorder(root->left, count, maxCount, ans); updateCount(root, count, maxCount, ans); inorder(root->right, count, maxCount, ans); } void updateCount(TreeNode* root, int& count, int& maxCount, vector<int>& ans) { if (pred && pred->val == root->val) ++count; else count = 1; if (count > maxCount) { maxCount = count; ans = {root->val}; } else if (count == maxCount) { ans.push_back(root->val); } pred = root; } }; ``` ### 98. Validate Binary Search Tree #### Approach 1: Iterative ```cpp class Solution { public: bool isValidBST(TreeNode* root) { return isValidBST(root, nullptr, nullptr); } private: bool isValidBST(TreeNode* root, TreeNode* minNode, TreeNode* maxNode) { if (!root) return true; if (minNode && root->val <= minNode->val) return false; if (maxNode && root->val >= maxNode->val) return false; return isValidBST(root->left, minNode, root) && isValidBST(root->right, root, maxNode); } }; ``` #### Approach 2: Recursive (stack) ```cpp class Solution { public: bool isValidBST(TreeNode* root) { stack<TreeNode*> stack; TreeNode* pred = nullptr; while (root || !stack.empty()) { while (root) { stack.push(root); root = root->left; } root = stack.top(), stack.pop(); if (pred && pred->val >= root->val) return false; pred = root; root = root->right; } return true; } }; ``` ### 104. Maximum Depth of Binary Tree ```cpp class Solution { public: int maxDepth(TreeNode* root) { if (!root) return 0; return 1 + max(maxDepth(root->left), maxDepth(root->right)); } }; ``` ### 236. Lowest Common Ancestor of a Binary Tree ```cpp class Solution { public: TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) { if (!root || root == p || root == q) return root; TreeNode* l = lowestCommonAncestor(root->left, p, q); TreeNode* r = lowestCommonAncestor(root->right, p, q); if (l && r) return root; return l ? l : r; } }; ``` ### 987. Vertical Order Traversal of a Binary Tree ```cpp class Solution { public: vector<vector<int>> verticalTraversal(TreeNode* root) { vector<vector<int>> ans; map<int, multiset<pair<int, int>>> xToSortedPairs; // {x: {(-y, val)}} dfs(root, 0, 0, xToSortedPairs); for (const auto& [_, pairs] : xToSortedPairs) { vector<int> vals; for (const auto& pair : pairs) vals.push_back(pair.second); ans.push_back(vals); } return ans; } private: void dfs(TreeNode* root, int x, int y, map<int, multiset<pair<int, int>>>& xToSortedPairs) { if (!root) return; xToSortedPairs[x].emplace(y, root->val); dfs(root->left, x - 1, y + 1, xToSortedPairs); dfs(root->right, x + 1, y + 1, xToSortedPairs); } }; ``` ## Two Pointers ### 42. Trapping Rain Water #### $O(n)$ space ```cpp class Solution { public: int trap(vector<int>& height) { const int n = height.size(); int ans = 0; vector<int> l(n); // l[i] := max(height[0..i]) vector<int> r(n); // r[i] := max(height[i..n)) for (int i = 0; i < n; ++i) l[i] = i == 0 ? height[i] : max(height[i], l[i - 1]); for (int i = n - 1; i >= 0; --i) r[i] = i == n - 1 ? height[i] : max(height[i], r[i + 1]); for (int i = 0; i < n; ++i) ans += min(l[i], r[i]) - height[i]; return ans; } }; ``` #### $O(1)$ space ```cpp class Solution { public: int trap(vector<int>& height) { if (height.empty()) return 0; int ans = 0; int l = 0; int r = height.size() - 1; int maxL = height[l]; int maxR = height[r]; while (l < r) if (maxL < maxR) { ans += maxL - height[l]; maxL = max(maxL, height[++l]); } else { ans += maxR - height[r]; maxR = max(maxR, height[--r]); } return ans; } }; ``` ## DFS ### 797. All Paths From Source to Target ```cpp class Solution { public: vector<vector<int>> allPathsSourceTarget(vector<vector<int>>& graph) { vector<vector<int>> ans; vector<int> path{0}; dfs(graph, 0, path, ans); return ans; } private: void dfs(const vector<vector<int>>& graph, int node, vector<int>& path, vector<vector<int>>& ans) { if (node == graph.size() - 1) { ans.push_back(path); return; } for (const int child : graph[node]) { path.push_back(child); dfs(graph, child, path, ans); path.pop_back(); } } }; ``` ### 430. Flatten a Multilevel Doubly Linked List #### Appraoch 1: Recursive ```cpp class Solution { public: Node* flatten(Node* head, Node* rest = nullptr) { if (!head) return rest; head->next = flatten(head->child, flatten(head->next, rest)); if (head->next) head->next->prev = head; head->child = nullptr; return head; } }; ``` #### Approach 2: Iterative ```cpp class Solution { public: Node* flatten(Node* head) { for (Node* curr = head; curr; curr = curr->next) if (curr->child) { Node* cachedNext = curr->next; curr->next = curr->child; curr->child->prev = curr; curr->child = nullptr; Node* tail = curr->next; while (tail->next) tail = tail->next; tail->next = cachedNext; if (cachedNext) cachedNext->prev = tail; } return head; } }; ``` ### 1274. Number of Ships in a Rectangle ```cpp /** * // This is Sea's API interface. * // You should not implement it, or speculate about its implementation * class Sea { * public: * bool hasShips(vector<int> topRight, vector<int> bottomLeft); * }; */ class Solution { public: int countShips(Sea sea, vector<int> topRight, vector<int> bottomLeft) { if (topRight[0] < bottomLeft[0] || topRight[1] < bottomLeft[1]) return 0; if (!sea.hasShips(topRight, bottomLeft)) return 0; // sea.hashShips(topRight, bottomLeft) == true if (topRight[0] == bottomLeft[0] && topRight[1] == bottomLeft[1]) return 1; const int mx = (topRight[0] + bottomLeft[0]) / 2; const int my = (topRight[1] + bottomLeft[1]) / 2; int ans = 0; // top right ans += countShips(sea, topRight, {mx + 1, my + 1}); // bottom right ans += countShips(sea, {topRight[0], my}, {mx + 1, bottomLeft[1]}); // top left ans += countShips(sea, {mx, topRight[1]}, {bottomLeft[0], my + 1}); // bottom left ans += countShips(sea, {mx, my}, bottomLeft); return ans; } }; ``` ### 242. Valid Anagram ```cpp class Solution { public: bool isAnagram(string s, string t) { if (s.length() != t.length()) return false; vector<int> count(128); for (const char c : s) ++count[c]; for (const char c : t) if (--count[c] < 0) return false; return true; } }; ``` ## Map ### 1583. Count Unhappy Friends ## Heap ### 407. Trapping Rain Water II ```cpp struct T { T(int i, int j, int h) : i(i), j(j), h(h) {} int i; int j; int h; // heightMap[i][j] or the height after filling water }; class Solution { public: int trapRainWater(vector<vector<int>>& heightMap) { const int m = heightMap.size(); const int n = heightMap[0].size(); const vector<int> dirs{0, 1, 0, -1, 0}; int ans = 0; auto compare = [](const T& a, const T& b) { return a.h > b.h; }; priority_queue<T, vector<T>, decltype(compare)> pq(compare); vector<vector<bool>> seen(m, vector<bool>(n)); for (int i = 0; i < m; ++i) { pq.emplace(i, 0, heightMap[i][0]); pq.emplace(i, n - 1, heightMap[i][n - 1]); seen[i][0] = true; seen[i][n - 1] = true; } for (int j = 1; j < n - 1; ++j) { pq.emplace(0, j, heightMap[0][j]); pq.emplace(m - 1, j, heightMap[m - 1][j]); seen[0][j] = true; seen[m - 1][j] = true; } while (!pq.empty()) { const auto [i, j, h] = pq.top(); pq.pop(); for (int k = 0; k < 4; ++k) { const int x = i + dirs[k]; const int y = j + dirs[k + 1]; if (x < 0 || x == m || y < 0 || y == n) continue; if (seen[x][y]) continue; if (heightMap[x][y] < h) { ans += h - heightMap[x][y]; pq.emplace(x, y, h); // fill the water on grid[x][y] } else { pq.emplace(x, y, heightMap[x][y]); } seen[x][y] = true; } } return ans; } }; ``` ### 692. Top K Frequent Words ```cpp class Solution { public: vector<string> topKFrequent(vector<string>& words, int k) { const int n = words.size(); vector<string> ans; vector<vector<string>> bucket(n + 1); unordered_map<string, int> count; for (const string& word : words) ++count[word]; for (const auto& [word, freq] : count) bucket[freq].push_back(word); for (int freq = n; freq > 0; --freq) { sort(begin(bucket[freq]), end(bucket[freq])); for (const string& word : bucket[freq]) { ans.push_back(word); if (ans.size() == k) return ans; } } throw; } }; ``` ### 1029. Two City Scheduling How much money can we save if we fly a person to A vs. B? To minimize the total cost, we should fly the person with the maximum saving to A, and with the minimum - to B. Example: [30, 100], [40, 90], [50, 50], [70, 50]. Savings: 70, 50, 0, -20. Obviously, first person should fly to A, and the last - to B. ```cpp class Solution { public: int twoCitySchedCost(vector<vector<int>>& costs) { const int n = costs.size() / 2; int ans = 0; // How much money can we save if we fly a person to A instead of B? // To save money, we should // 1) fly the person with the max saving to A // 2) fly the person with the min saving to B sort(begin(costs), end(costs), [](const auto& a, const auto& b) { // sort in descending order by the money saved // if we fly a person to A instead of B return a[1] - a[0] > b[1] - b[0]; }); for (int i = 0; i < n; ++i) ans += costs[i][0] + costs[i + n][1]; return ans; } }; ``` ## DP ### 403. Frog Jump ```cpp class Solution { public: bool canCross(vector<int>& stones) { const int n = stones.size(); // dp[i][j] := true if a frog can jumps to stones[i] with j units vector<vector<bool>> dp(n, vector<bool>(n + 1)); dp[0][1] = true; for (int i = 1; i < n; ++i) for (int j = 0; j < i; ++j) { const int k = stones[i] - stones[j]; if (k <= n && dp[j][k]) { dp[i][k - 1] = true; dp[i][k] = true; dp[i][k + 1] = true; } } return any_of(begin(dp.back()), end(dp.back()), [](bool val) { return val; }); } }; ``` ### 45. Jump Game II ```cpp class Solution { public: int jump(vector<int>& nums) { int ans = 0; int end = 0; int farthest = 0; for (int i = 0; i < nums.size() - 1; ++i) { farthest = max(farthest, i + nums[i]); if (farthest >= nums.size() - 1) { ++ans; break; } if (i == end) { ++ans; end = farthest; } } return ans; } }; ``` ### 140. Word Break II ```cpp class Solution { public: vector<string> wordBreak(string s, vector<string>& wordDict) { unordered_set<string> wordSet{begin(wordDict), end(wordDict)}; unordered_map<string, vector<string>> memo; return wordBreak(s, wordSet, memo); } private: vector<string> wordBreak(const string& s, const unordered_set<string>& wordSet, unordered_map<string, vector<string>>& memo) { if (memo.count(s)) return memo[s]; vector<string> ans; // 1 <= prefix.length() < s.length() for (int i = 1; i < s.length(); ++i) { const string& prefix = s.substr(0, i); const string& suffix = s.substr(i); if (wordSet.count(prefix)) for (const string& word : wordBreak(suffix, wordSet, memo)) ans.push_back(prefix + " " + word); } // contains whole string, so don't add any space if (wordSet.count(s)) ans.push_back(s); return memo[s] = ans; } }; ``` ### 322. Coin Change ```cpp class Solution { public: int coinChange(vector<int>& coins, int amount) { // dp[i] := fewest # of coins to make up i vector<int> dp(amount + 1, amount + 1); dp[0] = 0; for (const int coin : coins) for (int i = coin; i <= amount; ++i) dp[i] = min(dp[i], dp[i - coin] + 1); return dp[amount] == amount + 1 ? -1 : dp[amount]; } }; ``` ### 964. Least Operators to Express Number ```cpp class Solution { public: int leastOpsExpressTarget(int x, int target) { return dfs(x, target); } private: unordered_map<int, int> memo; int dfs(int x, int target) { if (memo.count(target)) return memo[target]; if (x > target) return min(2 * target - 1, 2 * (x - target)); if (x == target) return 0; long prod = x; int n = 0; while (prod < target) { prod *= x; ++n; } if (prod == target) return memo[target] = n; int ans = dfs(x, target - prod / x) + n; if (prod < 2 * target) ans = min(ans, dfs(x, prod - target) + n + 1); return memo[target] = ans; } }; ``` ## Greedy ### 56. Merge Intervals ```cpp class Solution { public: vector<vector<int>> merge(vector<vector<int>>& intervals) { vector<vector<int>> ans; sort(begin(intervals), end(intervals)); for (const auto& interval : intervals) if (ans.empty() || ans.back()[1] < interval[0]) ans.push_back(interval); else ans.back()[1] = max(ans.back()[1], interval[1]); return ans; } }; ``` ### 253. Meeting Rooms II ```cpp class Solution { public: int minMeetingRooms(vector<vector<int>>& intervals) { if (intervals.empty()) return 0; // store end times of each room priority_queue<int, vector<int>, greater<>> pq; sort(begin(intervals), end(intervals)); for (const auto& interval : intervals) { if (!pq.empty() && interval[0] >= pq.top()) pq.pop(); // no overlap, we can reuse the same room pq.push(interval[1]); } return pq.size(); } }; ``` ### 1583. Count Unhappy Friends ```cpp class Solution { public: int unhappyFriends(int n, vector<vector<int>>& preferences, vector<vector<int>>& pairs) { int ans = 0; vector<int> matches(n); vector<unordered_map<int, int>> prefer(n); for (const auto& pair : pairs) { const int x = pair[0]; const int y = pair[1]; matches[x] = y; matches[y] = x; } for (int i = 0; i < n; ++i) for (int j = 0; j < n - 1; ++j) prefer[i][preferences[i][j]] = j; for (int x = 0; x < n; ++x) for (const auto& [u, _] : prefer[x]) { const int y = matches[x]; const int v = matches[u]; if (prefer[x][u] < prefer[x][y] && prefer[u][x] < prefer[u][v]) { ++ans; break; } } return ans; } }; ```