LeetCode Medium

Ace your homework & exams now with Quizwiz!

Group Anagrams Given an array of strings strs, group the anagrams together. You can return the answer in any order. An Anagram is a word or phrase formed by rearranging the letters of a different word or phrase, typically using all the original letters exactly once. Input: strs = ["eat","tea","tan","ate","nat","bat"] Output: [["bat"],["nat","tan"],["ate","eat","tea"]]

1) Create hashmap and result vector 2) For each str in strs, set string to tmp string, sort tmp string, and add str to hashmap at key=tmp 3) Iterate through hashmap and add all vectors to result class Solution { public: ....vector<vector<string>> groupAnagrams(vector<string>& strs) { ........vector<vector<string>> result; ........unordered_map<string, vector<string>> map; ........ ........for (string str : strs) { ............string sorted_str = str; ............sort(sorted_str.begin(), sorted_str.end()); ............map[sorted_str].push_back(str); ........} ........ ........for (auto it : map) ............result.push_back(it.second); ........ ........return result; ....} };

Longest Palindromic Substring Given a string s, return the longest palindromic substring in s. Input: s = "babad" Output: "bab" Note: "aba" is also a valid answer.

Iterate through each char in string. Check if palindrome of style "aba" and return length1, check if palindrome of style "abba" and return length2. Get max(length1, length) and if max length > end - start, then we found a new longest palindrome, update start and end. Check palindrome by starting in the middle of the string and checking of middle-i == middle+i.

1937. Maximum Number of Points with Cost You are given an m x n integer matrix points (0-indexed). Starting with 0 points, you want to maximize the number of points you can get from the matrix. To gain points, you must pick one cell in each row. Picking the cell at coordinates (r, c) will add points[r][c] to your score. However, you will lose points if you pick a cell too far from the cell that you picked in the previous row. For every two adjacent rows r and r + 1 (where 0 <= r < m - 1), picking cells at coordinates (r, c1) and (r + 1, c2) will subtract abs(c1 - c2) from your score. Return the maximum number of points you can achieve. abs(x) is defined as: x for x >= 0. -x for x < 0. Example 1: Input: points = [[1,2,3],[1,5,1],[3,1,1]] 1,2,3 1,5,1 3,1,1 Output: 9 Explanation: The blue cells denote the optimal cells to pick, which have coordinates (0, 2), (1, 1), and (2, 0). You add 3 + 5 + 3 = 11 to your score. However, you must subtract abs(2 - 1) + abs(1 - 0) = 2 from your score. Your final score is 11 - 2 = 9. Example 2: Input: points = [[1,5],[2,3],[4,2]] Output: 11 Explanation: The blue cells denote the optimal cells to pick, which have coordinates (0, 1), (1, 1), and (2, 0). You add 5 + 3 + 4 = 12 to your score. However, you must subtract abs(1 - 1) + abs(1 - 0) = 1 from your score. Your final score is 12 - 1 = 11.

Approach 1: Brute Force class Solution { public: ....// Brute Force (Time: O(N*M*M), Space: O(N*M)) ....long long maxPoints(vector<vector<int>>& points) { ........long long res = 0; ........int n = points.size(); ........int m = points[0].size(); ........// memoization array storing max points for each cell ........vector<vector<long long>> cache(n, vector<long long>(m, -1)); ........ ........// Copy first row's values to memo cache ........// since recurrence relation requires calculating ........// points[i-1] ........for (int i = 0; i < m; i++) ............cache[0][i] = points[0][i]; ........ ........for (int i = 1; i < n; i++) { ............for (int j = 0; j < m; j++) { ................for (int k = 0; k < m; k++) { ....................// Calculate max points ....................// recurrence relation: ....................// curr value + prev row's value - abs(curr row's col - prev row's col) ....................cache[i][j] = max(cache[i][j], points[i][j] + cache[i - 1][k] - abs(k - j)); ................} ............} ........} ........// Result is the max value in the last row of cache ........for (int i = 0; i < m; i++) ........ res = max(res, cache[n - 1][i]); ........ ........return res; ....} };

1539. Kth Missing Positive Number Given an array arr of positive integers sorted in a strictly increasing order, and an integer k. Find the kth positive integer that is missing from this array. Example 1: Input: arr = [2,3,4,7,11], k = 5 Output: 9 Explanation: The missing positive integers are [1,5,6,8,9,10,12,13,...]. The 5th missing positive integer is 9. Example 2: Input: arr = [1,2,3,4], k = 2 Output: 6 Explanation: The missing positive integers are [5,6,7,...]. The 2nd missing positive integer is 6.

Approach 1: Brute Force (O(N)) // Time: O(N), Space: O(1) class Solution { public: ....int findKthPositive(vector<int>& arr, int k) { ........// If kth missing num < arr[0] ........if (k <= arr[0] - 1) ............return k; ........ ........// Decrement k by nums before start of arr[0] ........k -= arr[0] - 1; ........ ........// search kth missing bet/ array nums ........int n = arr.size(); ........for (int i = 0; i < n - 1; i++) { ............// Number of missing nums - 1 since 0-indexed ............int currMissing = arr[i+1] - arr[i] - 1; ............ ............// If kth missing number is between ............// arr[i] and arr[i+1], return it ............if (k <= currMissing) ................return arr[i] + k; ............ ............k -= currMissing; ........} ........ ........// If missing number is greater than ........// last element in arr[n-1], return last element + k ........return arr[n-1] + k; ....} }; Approach 2: Binary Search O(log N) 1) The number of positive integers which are missing before the arr[idx] is equal to arr[idx] - idx - 1. 2) Binary search - if (arr[mid] - mid - 1 < k), search right half, else search left half. 3) If k not found in array bounds, then return k + left. class Solution { public: ....int findKthPositive(vector<int>& arr, int k) { ........int left = 0; ........int right = arr.size() - 1; ........ ........while (left <= right) { ............int mid = left + (right - left)/2; ............ ............// The number of positive integers which ............// are missing before the arr[idx] is ............// equal to arr[idx] - idx - 1. ............// array w/o missing ints = [1,2,3,4,5 ] ............// input array............= [2,3,4,7,11] ............// Before 4, theres arr[2]-2-1=4-2-1=1 missing int ............// Before 11, theres arr[4]-4-1=11-4-1=6 missing ints ............// ............// If the number of missing ints at idx=mid < k, ............// then search the right half ............if (arr[mid] - mid - 1 < k) ................left = mid + 1; ............else // search the left half ................right = mid - 1; ........} ........ ........// At the end of the loop, left = right + 1, ........// and the kth missing is in-between arr[right] and arr[left]. ........// The number of integers missing before arr[right] is ........// arr[right] - right - 1 --> ........// the number to return is ........// arr[right] + k - (arr[right] - right - 1) = k + left ........// If k=8, 9 + 8 - (9 - 4 - 1) = 8 + 4 + 1 = 13 ........// arr: {5, 6, 7, 8, 9} ........// k: 9 / left: 5 / right: 4 ........return left + k; ....} };

Binary Tree Zigzag Level Order Traversal Given the root of a binary tree, return the zigzag level order traversal of its nodes' values. (i.e., from left to right, then right to left for the next level and alternate between). Input: root = [3,9,20,null,null,15,7] Output: [[3],[20,9],[15,7]]

Create a vector<list<int>>. In BFS, push_back when level is even, push_front when level is odd. After BFS is done, copy the elements from the vector<list<int>> to vector<vector<int>>. Return the result. class Solution { private: ....vector<list<int>> rows; ....vector<vector<int>> result; .... public: ....void bfs(TreeNode* root, int level) { ........if (!root) ............return; ........ ........if (result.size() == level) { ............result.push_back(vector<int>()); ............rows.push_back(list<int>()); ........} ........ ........if (level % 2 == 0) ............rows[level].push_back(root->val); ........else ............rows[level].push_front(root->val); ........ ........if (root->left) ............bfs(root->left, level + 1); ........if (root->right) ............bfs(root->right, level + 1); ....} .... ....vector<vector<int>> zigzagLevelOrder(TreeNode* root) { ........bfs(root, 0); ........ ........if (rows.size()) { ............for (int level = 0; level < rows.size(); level++) { ................for (int num : rows[level]) { ....................result[level].push_back(num); ................} ............} ........} ........ ........return result; ....} };

Majority Element Given an array nums of size n, return the majority element. The majority element is the element that appears more than ⌊n / 2⌋ times. You may assume that the majority element always exists in the array. Example 1: Input: nums = [3,2,3] Output: 3 Example 2: Input: nums = [2,2,1,1,1,2,2] Output: 2

Hash Map Time: O(n) Space: O(n) class Solution { public: ....int majorityElement(vector<int>& nums) { ........int major = 0; ........unordered_map<int, int> hashmap; ........ ........for (int i : nums) { ............hashmap[i]++; ............ ............if (hashmap[i] > hashmap[major]) ................major = i; ........} ........ ........return major; ....} };

Set Matrix Zeroes Given an m x n integer matrix matrix, if an element is 0, set its entire row and column to 0's, and return the matrix. You must do it in place.

Hash Set (O(N*M), fastest runtime) Create hash set and mark rows and cols when value=0. Then, iterate through the matrix, if the hash set contains the current row or col, then set matrix[row][col] = 0. Array Flags (O(1), space efficient solution) The idea is that we can use the first cell of every row and column as a flag. This flag would determine whether a row or column has been set to zero. This means for every cell instead of going to M+NM+N cells and setting it to zero we just set the flag in two cells. class Solution { public: ....void setZeroes(vector<vector<int>>& matrix) { ........bool isCol = false; ........int row_len = matrix.size(); ........int col_len = matrix[0].size(); ........ ........for (int r = 0; r < row_len; r++) { ............if (matrix[r][0] == 0) ................isCol = true; ............ ............for (int c = 1; c < col_len; c++) ................if (matrix[r][c] == 0) { ....................matrix[0][c] = matrix[r][0] = 0; ................} ........} ........ ........for (int r = 1; r < row_len; r++) { ............for (int c = 1; c < col_len; c++) { ................if (matrix[0][c] == 0 || matrix[r][0] == 0) { ....................matrix[r][c] = 0; ................} ............} ........} ........ ........if (matrix[0][0] == 0) { ............for (int c = 0; c < col_len; c++) { ................matrix[0][c] = 0; ............} ........} ........ ........if (isCol) { ............for (int r = 0; r < row_len; r++) { ................matrix[r][0] = 0; ............} ........} ....} };

Find Peak Element A peak element is an element that is strictly greater than its neighbors. Given an integer array nums, find a peak element, and return its index. If the array contains multiple peaks, return the index to any of the peaks. You may imagine that nums[-1] = nums[n] = -∞. You must write an algorithm that runs in O(log n) time. Input: nums = [1,2,3,1] Output: 2 Explanation: 3 is a peak element and your function should return the index number 2.

Iterate through nums from 0 to N-1. If nums[i] > nums[i+1], then return i. You don't need to test if nums[i] > nums[i-1] because nums[i-1] gets PRUNED from the result each time you test nums[i] > nums[i+1]. class Solution { public: ....int findPeakElement(vector<int>& nums) { ........for (int i = 0; i < nums.size() - 1; i++) { ............if (nums[i] > nums[i+1]) ................return i; ........} ........return nums.size() - 1; ....} };

Sum of Two Integers Given two integers a and b, return the sum of the two integers without using the operators + and -. Example 1: Input: a = 1, b = 2 Output: 3

Let's start by reducing the problem down to two simple cases: (1) Sum of two positive integers: x + y, where x > y. (2) Difference of two positive integers: x - y, where x > y. XOR is a sum of bits of x and y where at least one of the bits is not set. sum = (a ^ b) The next step is to find the carry. It contains the common set bits of x and y, shifted one bit to the left. I.e. it's logical AND of two input numbers, shifted one bit to the left: carry = (a & b) << 1 Difference of Two Positive Integers XOR is a difference of two integers without taking borrow into account. The next step is to find the borrow. It contains common set bits of y and unset bits of x: ((~x) & y) << 1 class Solution { public: ....int getSum(int a, int b) { ........while (b != 0) { ............int carry = (unsigned int)(a & b) << 1; ............a ^= b; ............b = carry; ........} ........ ........return a; ....} };

Fraction to Recurring Decimal Given two integers representing the numerator and denominator of a fraction, return the fraction in string format. If the fractional part is repeating, enclose the repeating part in parentheses. If multiple answers are possible, return any of them. It is guaranteed that the length of the answer string is less than 104 for all the given inputs. Example 1: Input: numerator = 1, denominator = 2 Output: "0.5"

Long Division Intuition The key insight here is to notice that once the remainder starts repeating, so does the divided result. Algorithm You will need a hash table that maps from the remainder to its position of the fractional part. Once you found a repeating remainder, you may enclose the reoccurring fractional part with parentheses by consulting the position from the table. The remainder could be zero while doing the division. That means there is no repeating fractional part and you should stop right away. Just like the question Divide Two Integers, be wary of edge cases such as negative fractions and nasty extreme case such as \dfrac{-2147483648}{-1}−1−2147483648​. Time: O(n) Space: O(length(divisor)) = O(n) class Solution { public: ....string fractionToDecimal(int numerator, int denominator) { ........if (!numerator) ............return "0"; ........ ........string fraction = ""; ........bool negative = (numerator < 0) ^ (denominator < 0); ........ ........if (negative) ............fraction += "-"; ........ ........long dividend = labs(numerator); ........long divisor = labs(denominator); ........ ........fraction += to_string(dividend / divisor); ........long remainder = dividend % divisor; ........ ........if (remainder == 0) ............return fraction; ........ ........fraction += "."; ........unordered_map<int, int> hashmap; ........ ........while (remainder != 0) { ............if (hashmap.find(remainder) != hashmap.end()) { ................fraction.insert(hashmap[remainder], "("); ................fraction += ")"; ................break; ............} ............hashmap[remainder] = fraction.length(); ............remainder *= 10; ............fraction += to_string(remainder / divisor); ............remainder %= divisor; ........} ........ ........return fraction; ....} };

2 DP Techniques

Recall that there are two different techniques we can use to implement a dynamic programming solution; memoization and tabulation. Memoization is where we add caching to a function (that has no side effects). In dynamic programming, it is typically used on recursive functions for a top-down solution that starts with the initial problem and then recursively calls itself to solve smaller problems. Tabulation uses a table to keep track of subproblem results and works in a bottom-up manner: solving the smallest subproblems before the large ones, in an iterative manner. Often, people use the words "tabulation" and "dynamic programming" interchangeably.

Search a 2D Matrix II Write an efficient algorithm that searches for a target value in an m x n integer matrix. The matrix has the following properties: Integers in each row are sorted in ascending from left to right. Integers in each column are sorted in ascending from top to bottom. Example 1: Input: matrix = [[1,4,7,11,15],[2,5,8,12,19],[3,6,9,16,22],[10,13,14,17,24],[18,21,23,26,30]], target = 5 Output: true

Search Space Reduction Because the rows and columns of the matrix are sorted (from left-to-right and top-to-bottom, respectively), we can prune \mathcal{O}(m)O(m) or \mathcal{O}(n)O(n) elements when looking at any particular value. class Solution { public: ....bool searchMatrix(vector<vector<int>>& matrix, int target) { ........if (!matrix.size()) ............return false; ........ ........int N = matrix.size(); ........int M = matrix[0].size(); ........int r = N-1; ........int c = 0; ........ ........while (r >= 0 && r < N && ............ c >= 0 && c < M) { ............if (matrix[r][c] == target) ................return true; ............else if (matrix[r][c] < target) ................c++; ............else ................r--; ........} ........ ........return false; ....} };

366. Find Leaves of Binary Tree Given the root of a binary tree, collect a tree's nodes as if you were doing this: Collect all the leaf nodes. Remove all the leaf nodes. Repeat until the tree is empty. Example 1: Input: root = [1,2,3,4,5] Output: [[4,5,3],[2],[1]] Explanation: [[3,5,4],[2],[1]] and [[3,4,5],[2],[1]] are also considered correct answers since per each level it does not matter the order on which elements are returned. Example 2: Input: root = [1] Output: [[1]]

Sol 1: DFS Time: O(N), Space: O(1) 1) Recursively call DFS function that calculates the current node's level and adds the current value to the result's level. If the result array's vector<int> hasn't been created for a level yet, add it. class Solution { public: ....vector<vector<int>> findLeaves(TreeNode* root) { ........vector<vector<int>> res; ........if (!root) ............return res; ........dfs(root, res); ........return res; ....} .... ....int dfs(TreeNode* root, vector<vector<int>>& res) { ........// If parent node is a leaf, then -1 ........if (!root) ............return -1; ........ ........int level = max(dfs(root->left, res), dfs(root->right, res)) + 1; ........ ........// Create level in result if needed ........if (level >= res.size()) ............res.push_back(vector<int>()); ........ ........// Add value to result ........res[level].push_back(root->val); ........ ........return level; ....} };

Construct Binary Tree from Preorder and Inorder Traversal Given two integer arrays preorder and inorder where preorder is the preorder traversal of a binary tree and inorder is the inorder traversal of the same tree, construct and return the binary tree. Input: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7] Output: [3,9,20,null,null,15,7]

The preorder array contains the root index and the inorder array contains the left and right pointers. root=8 // tree 8 4 5 3 7 3 // preorder 8 [4 3 3 7] [5] // inorder [3 3 4 7] 8 [5] Create hash map of inorder and a preorder_index. Create a new function arrayToTree(preorder, int left, int right). In arrayToTree, create a new node based on the next preorder[preorder_index] value. Then, set left ptr to the left half of the inorder array and right ptr to the right half of the inorder array. class Solution { private: ....unordered_map<int, int> map; ....int poIdx = 0; .... public: ....TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) { ........for (int i = 0; i < inorder.size(); i++) ............map[inorder[i]] = i; ................ ........return arrayToTree(preorder, 0, preorder.size() - 1); ....} .... ....TreeNode* arrayToTree(vector<int>& preorder, int left, int right) { ........if (left > right) ............return NULL; ........ ........int num = preorder[poIdx++]; ........TreeNode* root = new TreeNode(num);........ ........root->left = arrayToTree(preorder, left, map[num] - 1); ........root->right = arrayToTree(preorder, map[num] + 1, right); ........return root; ....} };

Meeting Rooms II Given an array of meeting time intervals intervals where intervals[i] = [starti, endi], return the minimum number of conference rooms required. Example 1: Input: intervals = [[0,30],[5,10],[15,20]] Output: 2 Example 2: Input: intervals = [[7,10],[2,4]] Output: 1 Constraints: 1 <= intervals.length <= 104 0 <= starti < endi <= 106

Two Ordered Lists Create 2 lists containing the sorted start and end times. You can use sort() but that's O(n*log(n)). Better to use a map since that's O(log(n)). Then, iterate through the 2 lists and increment count if start < end and move start iterator++; else decrement count and move end iterator++. Set maxCount. Return maxCount. Alternatively, use a min heap (priority queue) instead of an ordered map. intrvls = [[0,30],[5,10],[15,20]] mStart = [0 5 15] mEnd = [10 20 30] maxCount=2 class Solution { public: ....int minMeetingRooms(vector<vector<int>>& intervals) { ........int count = 0, maxCount = 0; ........map<int, int> mapping; ........ ........for (int i = 0; i < intervals.size(); i++) { ............int start = intervals[i][0]; ............int end = intervals[i][1]; ............mStart[start]++; ............mEnd[end]++; ........} ........ ........for (auto start = mStart.begin(), end = mEnd.begin(); ............ start != mStart.end() && end != mEnd.end();) { ............if (start->first < end->first) { ................start->second--; ................if (!start->second) ....................start++; ................count++; ............} else { ................end->second--; ................if (!end->second) ....................end++; ................count--; ............} ............maxCount = max(maxCount, count); ........} ........ ........return maxCount; ....} }; Optimized Map Solution Possible to use an ordered map to maintain the count of rooms using the start/end times. SO SMART! intrvls = [[0,30],[5,10],[15,20]] mStart = [0 5 15] mEnd = [10 20 30] [[0,1] [5,1] [10,-1] [15,1] [20,-1] [30,-1]] maxCount=2 class Solution { public: ....int minMeetingRooms(vector<vector<int>>& intervals) { ........int count = 0, maxCount = 0; ........map<int, int> mapping; ........ ........for (int i = 0; i < intervals.size(); i++) { ............mapping[intervals[i][0]]++; ............mapping[intervals[i][1]]--; ........} ........ ........for (auto i = mapping.begin(); .............i != mapping.end(); i++) { ............count += i->second; ............maxCount = max(maxCount, count); ........} ........ ........return maxCount; ....} }; Min Heap/Priority Queue class Solution { public: int minMeetingRooms(vector<vector<int>>& intervals) { int count = 0, maxCount = 0; sort(intervals.begin(), intervals.end(), [] (vector<int>& a, vector<int>&b) { return a[0] < b[0]; }); priority_queue<int, vector<int>, greater<int>> minHeap; for (vector<int> v : intervals) { if (!minHeap.empty() && minHeap.top() <= v[0]) minHeap.pop(); minHeap.push(v[1]); } return minHeap.size(); } };

Add Two Numbers You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order, and each of their nodes contains a single digit. Add the two numbers and return the sum as a linked list. You may assume the two numbers do not contain any leading zero, except the number 0 itself. Input: l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9] Output: [8,9,9,9,0,0,0,1]

Update l1 as you add up the numbers from left to right. If l1 == NULL and l2 != NULL, then have l1->next = l2. class Solution { public: ....ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) { ........ListNode *head = l1, *prev; ........int carry = 0, sum; ........ ........while (l1 || l2 || carry) { ............sum = (l1 ? l1->val : 0) + (l2 ? l2->val : 0) + carry; ............carry = sum > 9; ............ ............if (l1) { ................l1->val = sum % 10; ............} else if (l2) { ................l2->val = sum % 10; ................prev->next = l2; ............} else if (sum) { ................ListNode* node = new ListNode(1); ................prev->next = node; ............} ............ ............prev = l1 ? l1 : l2; ............l1 = l1 ? l1->next : l1; ............l2 = l2 ? l2->next : l2; ........} ........ ........return head; ....} };

Flatten 2D Vector Design an iterator to flatten a 2D vector. It should support the next and hasNext operations. Implement the Vector2D class: Vector2D(int[][] vec) initializes the object with the 2D vector vec. next() returns the next element from the 2D vector and moves the pointer one step forward. You may assume that all the calls to next are valid. hasNext() returns true if there are still some elements in the vector, and false otherwise. Example 1: Input ["Vector2D", "next", "next", "next", "hasNext", "hasNext", "next", "hasNext"] [[[[1, 2], [3], [4]]], [], [], [], [], [], [], []] Output [null, 1, 2, 3, true, true, 4, false] Explanation Vector2D vector2D = new Vector2D([[1, 2], [3], [4]]); vector2D.next(); // return 1 vector2D.next(); // return 2 vector2D.next(); // return 3 vector2D.hasNext(); // return True vector2D.hasNext(); // return True vector2D.next(); // return 4 vector2D.hasNext(); // return False

class Vector2D { private: ....vector<int> vec2d; ....int curr; .... public: ....Vector2D(vector<vector<int>>& vec) { ........for (vector<int> r : vec) { ............for (int num : r) { ................vec2d.push_back(num); ............} ........} ........curr = -1; ....} .... ....int next() { ........curr++; ........if (curr < vec2d.size()) ............return vec2d[curr]; ........return 0; ....} .... ....bool hasNext() { ........return (curr + 1) < vec2d.size(); ....} };

Top K Frequent Elements Given an integer array nums and an integer k, return the k most frequent elements. You may return the answer in any order. Input: nums = [1,1,1,2,2,3], k = 2 Output: [1,2]

2 Hash Maps Create hash map counting the frequency of each value. Then, create a new mapCount with key=frequency and value=key. Then, iterate through mapCount in reverse and append the last k mapCount.value to the result vector. class Solution { public:.... ....vector<int> topKFrequent(vector<int>& nums, int k) { ........map<int, int> m; ........map<int, vector<int>> mCount; ........vector<int> result; ........ ........// Create hash map storing map<nums[i], frequency>> ........for (int i : nums) ............m[i]++; ........ ........// Create hash map storing map<frequency, nums[i]>> ........for (auto i : m) ............mCount[i.second].push_back(i.first); ........ ........// Append top k most frequenct nums to result ........for (auto i = mCount.rbegin(); i != mCount.rend() && k > 0; i++) { ............vector<int> v = i->second; ............for (int j = 0; j < v.size() && k > 0; j++) { ................result.push_back(v[j]); ................k--; ............} ........} ........ ........return result; ....} };

Sort Colors Given an array nums with n objects colored red, white, or blue, sort them in-place so that objects of the same color are adjacent, with the colors in the order red, white, and blue. We will use the integers 0, 1, and 2 to represent the color red, white, and blue, respectively. You must solve this problem without using the library's sort function. Input: nums = [2,0,2,1,1,0] Output: [0,0,1,1,2,2]

3 Pointers Create 3 pointers for start, end, and iterator. Loop through from 0 to N. If nums[i] == 0, swap nums[i] and nums[start]. If nums[i] == 2, swap nums[i] and nums[start]. class Solution { public: ....void sortColors(vector<int>& nums) { ........if (!nums.size()) ............return; ........ ........int start = 0; ........int end = nums.size() - 1; ........int i = 0; ........ ........while (i <= end && start <= end) { ............if (nums[i] == 0) { ................swap(nums[i], nums[start]); ................start++; ................i++; ............} else if (nums[i] == 2) { ................swap(nums[i], nums[end]); ................end--; ............} else { ................i++; ............} ........} ....} }; Hash Map Create an ordered hash map of nums. Then, iterate through nums from 0 to N and replace nums[i] with map_itr->first and decrement map_itr->second. If map_itr->second < 1, then increment map_itr to move onto the next key. class Solution { public: ....void sortColors(vector<int>& nums) { ........map<int, int> mapping; ........ ........for (int i : nums) ............mapping[i]++; ........ ........auto itr = mapping.begin(); ........for (int i = 0; i < nums.size() && itr != mapping.end(); i++) { ............nums[i] = itr->first; ............itr->second--; ............if (itr->second < 1) ................itr++; ........} ....} };

1143. Longest Common Subsequence Given two strings text1 and text2, return the length of their longest common subsequence. If there is no common subsequence, return 0. A subsequence of a string is a new string generated from the original string with some characters (can be none) deleted without changing the relative order of the remaining characters. For example, "ace" is a subsequence of "abcde". A common subsequence of two strings is a subsequence that is common to both strings. Example 1: Input: text1 = "abcde", text2 = "ace" Output: 3 Explanation: The longest common subsequence is "ace" and its length is 3. Example 2: Input: text1 = "abc", text2 = "abc" Output: 3 Explanation: The longest common subsequence is "abc" and its length is 3. Example 3: Input: text1 = "abc", text2 = "def" Output: 0 Explanation: There is no such common subsequence, so the result is 0.

Approach 1: DP 1) Init 2d matrix text1.size+1 * text2.size+1 2) DP bottom up approach. Double for-loop starting from bottom-right corner to top-left corner. If chars match, dp[i][j] = dp[i+1][j+1] + 1 = diagonal bottom-right cell + 1. If chars don't match, dp[i][j] = max(bottom cell, right cell) = max(dp[i+1][j], dp[i][j+1]) 3) Return dp[0][0] class Solution { public: ..../*a c e .... _______ ....a|3.... 0 ....b| 2 0 ....c| 2 0 ....d|....1 0 ....e|....1 0 .... 0 0 0 ....- Move diagonally to bottom-right when letter matches ....- Move to max(right cell, bottom cell) when letter doesn't match ....*/ ....int longestCommonSubsequence(string text1, string text2) { ........int n = text1.length(); ........int m = text2.length(); ........// Init 2d dp array to 0 so that when chars don't ........// match, then we take max bet/ bottom and right cells. ........// Size is n+1*m+1 because we need the outside bounds ........// to be 0 when calculating the walls of the DP matrix ........vector<vector<int>> dp(n + 1, vector<int>(m + 1, 0)); ........ ........// DP bottom-up approach ........for (int i = n - 1; i >= 0; i--) { ............for (int j = m - 1; j >= 0; j--) { ................if (text1[i] == text2[j]) { ....................// If chars match, then ....................// dp[i][j] = diagonal bottom-right value + 1 ....................dp[i][j] = dp[i + 1][j + 1] + 1; ................} else { ....................// If chars don't match, then ....................// dp[i][j] = max(1 cell lower, 1 cell right) ....................dp[i][j] = max(dp[i + 1][j], dp[i][j + 1]); ................} ............} ........} ........ ........return dp[0][0]; ....} };

583. Delete Operation for Two Strings Given two strings word1 and word2, return the minimum number of steps required to make word1 and word2 the same. In one step, you can delete exactly one character in either string. Example 1: Input: word1 = "sea", word2 = "eat" Output: 2 Explanation: You need one step to make "sea" to "ea" and another step to make "eat" to "ea". Example 2: Input: word1 = "leetcode", word2 = "etco" Output: 4 Constraints: 1 <= word1.length, word2.length <= 500 word1 and word2 consist of only lowercase English letters.

Approach 1: DP Bottom-Up 1) Init (word1.len+1) * (word2.len+1) size dp array, initialized to 0. 2) Init dp[0][i] first row and dp[0][i] first col such that first letter is an empty string. 3) For each row and for each col, if word1[col-1] == word2[row-1], then dp[i][j] = dp[row-1][col-1]; else, dp[i][j] = min(left cell, upper cell) + 1. 4) Return dp[rows][cols] bottom-right cell. /* DP Bottom-Up approach " e a t "|0 1 2 3 <- Init row s|1 2 . . e|2 . . . a|3 . . . ^-init col - If word1[i] == word2[j], dp[i][j] = dp[i-1][j-1] - If word1[i] != word2[j], dp[i][j] = max(dp[i-1][j], dp[i][j-1]) + 1 " e a t "{0, 1, 2, 3}, s{1, 2, 3, 4}, e{2, 1, 4, 5}, a{3, 4, 5, 4}} */ class Solution { public: ....int minDistance(string word1, string word2) { ........int cols = word1.length(); ........int rows = word2.length(); ........vector<vector<int>> dp(rows+1, vector<int>(cols+1, 0)); ........ ........// Init dp taking into account empty ........// string at col/row 0 ........// "" e a t ........//""{0, 1, 2, 3}, ........// s{1, ., ., .}, ........// e{2, ., ., .}, ........// a{3, ., ., .}} ........for (int r = 0; r <= rows; r++) ............dp[r][0] = r; ........ ........for (int c = 0; c <= cols; c++) ............dp[0][c] = c; ........ ........//...."" e a t ........// ""{0, 1, 2, 3} ........// s{1, 2, 3, 4} ........// e{2, 1, 2, 3} ........// a{3, 2, 1, 2} ........for (int r = 1; r <= rows; r++) { ............for (int c = 1; c <= cols; c++) { ................if (word1[c-1] == word2[r-1]) { ....................// If chars match, set ....................// curr dp = diagonal upper-left cell ....................dp[r][c] = dp[r-1][c-1]; ................} else { ....................// If chars don't match, set ....................// curr dp = min(left cell, upper cell) + 1 ....................dp[r][c] = min(dp[r-1][c], dp[r][c-1]) + 1; ................} ............} ........} ........ ........return dp[rows][cols]; ....} };

931. Minimum Falling Path Sum Given an n x n array of integers matrix, return the minimum sum of any falling path through matrix. A falling path starts at any element in the first row and chooses the element in the next row that is either directly below or diagonally left/right. Specifically, the next element from position (row, col) will be (row + 1, col - 1), (row + 1, col), or (row + 1, col + 1). Example 1: Input: matrix = [[2,1,3],[6,5,4],[7,8,9]] 2,1,3 6,5,4 7,8,9 Output: 13 Explanation: There are two falling paths with a minimum sum as shown - [1,5,7] = 13 and [1,4,8] = 13. Example 2: Input: matrix = [[-19,57],[-40,-5]] Output: -59 Explanation: The falling path with a minimum sum is shown.

Approach 1: DP Top-Down Approach For each row/col, calculate the min path sum for each element using Top-Down DP approach. Last row will contain total min path sums. dp[row][col] = max((row + 1, col - 1), (row + 1, col), (row + 1, col + 1)) Use max(0, j-1) to bound check left col. Use min(matrix.size() - 1, j+1) to bound check right col. class Solution { public: ....int minFallingPathSum(vector<vector<int>>& matrix) { ........int res = INT_MAX; ........int n = matrix.size(); ........int m = matrix[0].size(); ........// Ideally, we need a DP matrix of size NxM that's ........// initialized to a copy of matrix. However, ........// we can just overwrite matrix with the path sum to ........// save space. ........ ........// Calculate the min path sum for each element ........// using Top-Down DP approach. Last row will ........// contain total min path sums. ........// dp[row][col] = max((row + 1, col - 1), ........//....................(row + 1, col), ........//....................(row + 1, col + 1)) ........// Do bound checking using max/min. ........for (int i = 1; i < n; i++) { ............for (int j = 0; j < m; j++) { ................matrix[i][j] += min({ ....................matrix[i-1][max(0, j-1)], ....................matrix[i-1][j], ....................matrix[i-1][min(m-1, j+1)] }); ............} ........} ........ ........// Result is the max value in the last row ........for (int i : matrix[n - 1]) ............res = min(res, i); ........ ........return res; ....} };

57. Insert Interval You are given an array of non-overlapping intervals intervals where intervals[i] = [starti, endi] represent the start and the end of the ith interval and intervals is sorted in ascending order by starti. You are also given an interval newInterval = [start, end] that represents the start and end of another interval. Insert newInterval into intervals such that intervals is still sorted in ascending order by starti and intervals still does not have any overlapping intervals (merge overlapping intervals if necessary). Return intervals after the insertion. Example 1: Input: intervals = [[1,3],[6,9]], newInterval = [2,5] Output: [[1,5],[6,9]] Example 2: Input: intervals = [[1,2],[3,5],[6,7],[8,10],[12,16]], newInterval = [4,8] Output: [[1,2],[3,10],[12,16]] Explanation: Because the new interval [4,8] overlaps with [3,5],[6,7],[8,10]. Constraints: 0 <= intervals.length <= 104 intervals[i].length == 2 0 <= starti <= endi <= 105 intervals is sorted by starti in ascending order. newInterval.length == 2 0 <= start <= end <= 105

Approach 1: Greedy 1) Iterate through intervals. If end of newInterval < start of current interval, push newInterval to result, add rest of intervals from i to end, and then return result. If class Solution { public: ....vector<vector<int>> insert(vector<vector<int>>& intervals, vector<int>& newInterval) { ........vector<vector<int>> res; ........int n = intervals.size(); ........ ........// If intervals is empty, return newInterval ........if (!n) { ............res.push_back(newInterval); ............return res; ........} ........ ........for (int i = 0; i < n; i++) { ............if (newInterval[1] < intervals[i][0]) { ................// If end of newInterval < start of current interval, ................ ................// Add newInterval to the start of result ................res.push_back(newInterval); ................ ................// Copy rest of the array after i to result ................for (int j = i; j < n; j++) ....................res.push_back(intervals[j]); ................ ................return res; ............} else if (intervals[i][1] < newInterval[0]) { ................// If end of newInterval < start of current interval ................ ................// In example below, 2<4 from [1,2] < [4,8]. ................// Therefore, add [1,2] to result. ................//................ i ................// intervals....= [[1,2],[3,5],[6,7],[8,10],[12,16]] ................// newIntervals =........[4,8] ................res.push_back(intervals[i]); ............} else { ................// Merge intervals[i] and newInterval ................newInterval = { min(newInterval[0], intervals[i][0]), ................................max(newInterval[1], intervals[i][1]) }; ............} ........} ........ ........// If any intervals are leftover, add it to result ........// intervals = [[1,5]] ........// newInterval = [2,3] -> merge to newInterval=[1,5] and exit for loop ........res.push_back(newInterval); ................ ........return res; ....} };

436. Find Right Interval You are given an array of intervals, where intervals[i] = [starti, endi] and each starti is unique. The right interval for an interval i is an interval j such that startj >= endi and startj is minimized. Return an array of right interval indices for each interval i. If no right interval exists for interval i, then put -1 at index i. Example 1: Input: intervals = [[1,2]] Output: [-1] Explanation: There is only one interval in the collection, so it outputs -1. Example 2: Input: intervals = [[3,4],[2,3],[1,2]] Output: [-1,0,1] Explanation: There is no right interval for [3,4]. The right interval for [2,3] is [3,4] since start0 = 3 is the smallest start that is >= end1 = 3. The right interval for [1,2] is [2,3] since start1 = 2 is the smallest start that is >= end2 = 2. Example 3: Input: intervals = [[1,4],[2,3],[3,4]] Output: [-1,2,-1] Explanation: There is no right interval for [1,4] and [3,4]. The right interval for [2,3] is [3,4] since start2 = 3 is the smallest start that is >= end1 = 3.

Approach 1: Hashmap class Solution { public: ....vector<int> findRightInterval(vector<vector<int>>& intervals) { ........int n = intervals.size(); ........vector<int> res(n); ........map<int, int> intMap; ........ ........for (int i = 0; i < n; i++) ............intMap[intervals[i][0]] = i; ........ ........for (int i = 0; i < n; i++) { ............// Find the element in map that contains end interval. ............// If end interval is not in hashmap, set iterator ............// to the next biggest value ............auto it = intMap.lower_bound(intervals[i][1]); ............ ............// If iterator is not in the map, set result as -1; ............// Else, set result as the index ............if (it == intMap.end()) ................res[i] = -1; ............else ................res[i] = it->second; ........} ........ ........return res; ....} };

Ksum Given an array nums of n integers, return an array of all the unique quadruplets [nums[a], nums[b], nums[c], nums[d]] such that: 0 <= a, b, c, d < n a, b, c, and d are distinct. nums[a] + nums[b] + nums[c] + nums[d] == target You may return the answer in any order. Example 1: Input: nums = [1,0,-1,0,-2,2], target = 0 Output: [[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]] Example 2: Input: nums = [2,2,2,2,2], target = 8 Output: [[2,2,2,2]]

Approach 1: Hashset class Solution { public: ....vector<vector<int>> fourSum(vector<int>& nums, int target) { ........sort(nums.begin(), nums.end()); ........return kSum(nums, target, 0, 4); ....} .... ....vector<vector<int>> kSum(vector<int> &nums, int target, int start, int k) { ........vector<vector<int>> result; ........ ........// If we have run out of numbers to add, return result ........if (start == nums.size()) ............return result; ........ ........// There are k remaining values to add to the sum. The ........// average of these values is a least target/k. ........int avg_val = target / k; ........ ........// We cannot obtain a sum of target if the smallest value ........// in nums is greater than target/k or if the largest ........// value in nums is smaller than target/k. ........if (nums[start] > avg_val || avg_val > nums.back()) ............return result; ........ ........if (k == 2) ............return twoSum(nums, target, start); ........ ........for (int i = start; i < nums.size(); i++) { ............if (i == start || nums[i-1] != nums[i]) { ................for (vector<int>& subset : kSum(nums, target - nums[i], i + 1, k - 1)) { ....................result.push_back({ nums[i] }); ....................result.back().insert(result.back().end(), subset.begin(), subset.end()); ................} ............} ........} ........ ........return result; ....} .... ....vector<vector<int>> twoSum(vector<int>& nums, int target, int start) { ........vector<vector<int>> result; ........unordered_set<int> s; ........ ........for (int i = start; i < nums.size(); i++) { ............if (result.empty() || result.back()[1] != nums[i]) { ................int comp = target - nums[i]; ................if (s.count(comp)) { ....................result.push_back({ comp, nums[i] }); ................} ............} ............s.insert(nums[i]); ........} ........ ........return result; ....} };

160. Intersection of Two Linked Lists Given the heads of two singly linked-lists headA and headB, return the node at which the two lists intersect. If the two linked lists have no intersection at all, return null. For example, the following two linked lists begin to intersect at node c1: The test cases are generated such that there are no cycles anywhere in the entire linked structure. Note that the linked lists must retain their original structure after the function returns. Custom Judge: The inputs to the judge are given as follows (your program is not given these inputs): intersectVal - The value of the node where the intersection occurs. This is 0 if there is no intersected node. listA - The first linked list. listB - The second linked list. skipA - The number of nodes to skip ahead in listA (starting from the head) to get to the intersected node. skipB - The number of nodes to skip ahead in listB (starting from the head) to get to the intersected node. The judge will then create the linked structure based on these inputs and pass the two heads, headA and headB to your program. If you correctly return the intersected node, then your solution will be accepted. Example 1: Input: intersectVal = 8, listA = [4,1,8,4,5], listB = [5,6,1,8,4,5], skipA = 2, skipB = 3 Output: Intersected at '8' Explanation: The intersected node's value is 8 (note that this must not be 0 if the two lists intersect). From the head of A, it reads as [4,1,8,4,5]. From the head of B, it reads as [5,6,1,8,4,5]. There are 2 nodes before the intersected node in A; There are 3 nodes before the intersected node in B. Example 2: Input: intersectVal = 2, listA = [1,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1 Output: Intersected at '2' Explanation: The intersected node's value is 2 (note that this must not be 0 if the two lists intersect). From the head of A, it reads as [1,9,1,2,4]. From the head of B, it reads as [3,2,4]. There are 3 nodes before the intersected node in A; There are 1 node before the intersected node in B. Example 3: Input: intersectVal = 0, listA = [2,6,4], listB = [1,5], skipA = 3, skipB = 2 Output: No intersection Explanation: From the head of A, it reads as [2,6,4]. From the head of B, it reads as [1,5]. Since the two lists do not intersect, intersectVal must be 0, while skipA and skipB can be arbitrary values. Explanation: The two lists do not intersect, so return null.

Approach 1: Hashset Time: O(N) Space: O(N) class Solution { public: ....ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) { ........unordered_set<ListNode*> nodeSet; ........ListNode *currA = headA, *currB = headB; ........ ........while (currA) { ............nodeSet.insert(currA); ............currA = currA->next; ........} ........ ........while (currB) { ............if (nodeSet.count(currB)) ................return currB;............ ............currB = currB->next; ........} ........ ........return NULL; ....} }; Approach 2: Two Pointers (OPTIMAL) 1) Init pA=headA and pB=headB 2) Iterate the length of each list. At the end of A, swap list ptrs such that pA=headB; likewise for B. 3) After iterating each list, the remaining values will have equal length in list A and B. One of these values is the insection if pA==pB. 4) Return pA Time: O(N) Space: O(1) /* INPUT: 8 [4,1,8,4,5] [5,6,1,8,4,5] 2 3 EXPLANATION: 1) Iterate over the length of headA and headB A 4,1,8,4,5 B 5,6,1,8,4,5 2) After setting pA = headB, then iterate over the remaining values in the longer list. // End of iterating list A ........A 4,1,8,4,5 ........B 5,6,1,8,4,5 // After iterating the shorter list A, have A point to headB. 4,1,8,4,5 A........ B 5,6,1,8,4,5 // After iterating the longer list B, have B point to headA. At this // point, the remaining length of list A and B are equal, and one of // the remaining values is the intersection (if pA == pB) B->-> 4,1,8,4,5 A->-> 5,6,1,8,4,5 // Since pA == pB, return pA. ....B* 4,1,8,4,5 .... A* 5,6,1,8,4,5 */ class Solution { public: ....ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) { ........ListNode *pA = headA; ........ListNode *pB = headB; ........while (pA != pB) { ............pA = !pA ? headB : pA->next; ............pB = !pB ? headA : pB->next; ........} ........return pA; ....} };

92. Reverse Linked List II Given the head of a singly linked list and two integers left and right where left <= right, reverse the nodes of the list from position left to position right, and return the reversed list. Example 1: Input: head = [1,2,3,4,5], left = 2, right = 4 Output: [1,4,3,2,5] Example 2: Input: head = [5], left = 1, right = 1 Output: [5] Constraints: The number of nodes in the list is n. 1 <= n <= 500 -500 <= Node.val <= 500 1 <= left <= right <= n

Approach 1: Iterative Reversal 1) Find prev node pointing to left index and left index itself 2) Set pointers that will fix the start and end connections (start=curr, end=prev) 3) Reverse nodes from left to right index 4) Fix start and end connections 5) Return head class Solution { public: ....ListNode* reverseBetween(ListNode* head, int left, int right) { ........if (!head) ............return NULL; ........ ........ListNode *curr = head, *prev = NULL, *tmp; ........ ........// Find prev node pointing to left index ........// and left index itself ........// 1(prev)->2(curr)->3->4->5 ........for (int i = 0; i < left - 1; i++) { ............prev = curr; ............curr = curr->next; ........} ........ ........// Pointers that will fix the start and end connections ........// 1(start/prev)->2(end/curr)->3->4->5 ........ListNode *start = prev, *end = curr; ........ ........// Reverse nodes from left to right index ........// curr: [2,3,4,5] ........// prev: [1,2,3,4,5] ........for (int i = left; i <= right; i++) { ............tmp = curr->next; ............curr->next = prev; ............prev = curr; ............curr = tmp; ........} ........ ........// Fix start and end connections ........if (start) ............// 1(start)<-2(tail)<-3<-4(prev) 5 ............// 1->4->3->2 5 ............start->next = prev; ........else ............// If start == NULL, set head to prev ............// start: [] ............// curr: [] ............// prev: [5,3] ............head = prev; ........ ........// 1->4->3->(2->5) ........end->next = curr; ........ ........return head; ....} };

1574. Shortest Subarray to be Removed to Make Array Sorted Given an integer array arr, remove a subarray (can be empty) from arr such that the remaining elements in arr are non-decreasing. Return the length of the shortest subarray to remove. A subarray is a contiguous subsequence of the array. Example 1: Input: arr = [1,2,3,10,4,2,3,5] Output: 3 Explanation: The shortest subarray we can remove is [10,4,2] of length 3. The remaining elements after that will be [1,2,3,3,5] which are sorted. Another correct solution is to remove the subarray [3,10,4]. Example 2: Input: arr = [5,4,3,2,1] Output: 4 Explanation: Since the array is strictly decreasing, we can only keep a single element. Therefore we need to remove a subarray of length 4, either [5,4,3,2] or [4,3,2,1]. Example 3: Input: arr = [1,2,3] Output: 0 Explanation: The array is already non-decreasing. We do not need to remove any elements.

Approach 1: Left + Middle Removed + Right Subarray Time: O(N), Space(O(1) https://leetcode.com/problems/shortest-subarray-to-be-removed-to-make-array-sorted/discuss/830480/C%2B%2B-O(N)-Sliding-window-Explanation-with-Illustrations 1) Init right ptr = arr.size() - 1 2) Iterate arr from right to left while arr[r-1] <= arr[r] 3) Set res = right index 4) Iterate arr from left to right while (left==0 OR arr[left-1] < arr[left]), then increment right ptr while arr[left] > arr[right] so make left subarray <= right subarray. Update length result min(length, right - left - 1). 5) Return length result // Input l............ r 1,5,7,10,7,5,7,1,6,12,15 */ class Solution { public: ....int findLengthOfShortestSubarray(vector<int>& arr) { ........int n = arr.size(); ........int r = n - 1; ........int res = 0; ........ ........// Find longest valid subarray from right to left ........//............r ........// 1,3,2,10,4,2,3,5 ........for (; r > 0 && arr[r-1] <= arr[r]; r--); ........ ........// Init result to r since the left subarray [0, r-1] ........// and right subarray [r, n] will be at most length r ........res = r; ........ ........// Find longest valid subarray from left to right. ........// l........ r ........// 1,3,2,10,4,2,3,5 ........for (int l = 0; l < r && (l == 0 || arr[l-1] <= arr[l]); l++) { ............// Whenever we do left++, we must shift right ptr ............// right while arr[left] > arr[right] to guarantee ............// left subarray <= right subarray. ............// l........->r // l=1, r=6 ............// 1,3,2,10,4,2,3,5 ............while (r < n && arr[l] > arr[r]) ................r++; ............ ............// Update result ............// result = 6 - 1 - 1 ............res = min(res, r - l - 1); ........} ........ ........return res; ....} };

442. Find All Duplicates in an Array Given an integer array nums of length n where all the integers of nums are in the range [1, n] and each integer appears once or twice, return an array of all the integers that appears twice. You must write an algorithm that runs in O(n) time and uses only constant extra space. Example 1: Input: nums = [4,3,2,7,8,2,3,1] Output: [2,3] Example 2: Input: nums = [1,1,2] Output: [1] Example 3: Input: nums = [1] Output: []

Approach 1: Mark Visited Elements in the Input Array itself 1) Mark the nums[num] value as visited by changing it to negative. Similar to swap sort for arrays of size n with values [1,n]. 2) Iterate through nums again and if nums[abs(num]-1] > 0, then add to result and mark nums[abs(num]-1] as visited. class Solution { public: ....vector<int> findDuplicates(vector<int>& nums) { ........vector<int> ans; ........// Mark the nums[num] value as visited ........// by changing it to negative. ........// Similar to swap sort for arrays of size n ........// with values [1,n]. ........for (auto num : nums) ............nums[abs(num) - 1] *= -1; ........// If num is positive, add to result ........for (auto num : nums) { ............if (nums[abs(num) - 1] > 0) { ................ans.push_back(abs(num)); ................// Mark nums[num] value as visited ................nums[abs(num) - 1] *= -1; ............} ........} ........return ans; ....} };

1834. Single-Threaded CPU You are given n​​​​​​ tasks labeled from 0 to n - 1 represented by a 2D integer array tasks, where tasks[i] = [enqueueTimei, processingTimei] means that the i​​​​​​th​​​​ task will be available to process at enqueueTimei and will take processingTimei to finish processing. You have a single-threaded CPU that can process at most one task at a time and will act in the following way: If the CPU is idle and there are no available tasks to process, the CPU remains idle. If the CPU is idle and there are available tasks, the CPU will choose the one with the shortest processing time. If multiple tasks have the same shortest processing time, it will choose the task with the smallest index. Once a task is started, the CPU will process the entire task without stopping. The CPU can finish a task then start a new one instantly. Return the order in which the CPU will process the tasks. Example 1: Input: tasks = [[1,2],[2,4],[3,2],[4,1]] Output: [0,2,3,1] Explanation: The events go as follows: - At time = 1, task 0 is available to process. Available tasks = {0}. - Also at time = 1, the idle CPU starts processing task 0. Available tasks = {}. - At time = 2, task 1 is available to process. Available tasks = {1}. - At time = 3, task 2 is available to process. Available tasks = {1, 2}. - Also at time = 3, the CPU finishes task 0 and starts processing task 2 as it is the shortest. Available tasks = {1}. - At time = 4, task 3 is available to process. Available tasks = {1, 3}. - At time = 5, the CPU finishes task 2 and starts processing task 3 as it is the shortest. Available tasks = {1}. - At time = 6, the CPU finishes task 3 and starts processing task 1. Available tasks = {}. - At time = 10, the CPU finishes task 1 and becomes idle. Example 2: Input: tasks = [[7,10],[7,12],[7,5],[7,4],[7,2]] Output: [4,3,2,0,1] Explanation: The events go as follows: - At time = 7, all the tasks become available. Available tasks = {0,1,2,3,4}. - Also at time = 7, the idle CPU starts processing task 4. Available tasks = {0,1,2,3}. - At time = 9, the CPU finishes task 4 and starts processing task 3. Available tasks = {0,1,2}. - At time = 13, the CPU finishes task 3 and starts processing task 2. Available tasks = {0,1}. - At time = 18, the CPU finishes task 2 and starts processing task 0. Available tasks = {1}. - At time = 28, the CPU finishes task 0 and starts processing task 1. Available tasks = {}. - At time = 40, the CPU finishes task 1 and becomes idle.

Approach 1: Min Heap [[1,2],[2,4],[3,2],[4,1]] T1-Task 0 Start T2-Task 0. {Task Min Heap = 1} T3-Task 0 Done. {Task Min Heap = 1,2} T3-Task 2 Start {Task Min Heap = 1} T4-Task 2 {Task Min Heap = 1,3} T5-Task 2 Done {Task Min Heap = 1,3} T5-Task 3 Start {Task Min Heap = 1} T6-Task 3 Done {Task Min Heap = 1} T6-Task 1 Start {Task Min Heap =} T7-Task 1 T8-Task 1 T9-Task 1 T10-Task 1 Done. Exit DSA: - Min heap to track pending tasks Sol 1: 1) Sort tasks by enqueue time 2) Add index to each task 3) Sort tasks by enqueue time 4) Create min heap<processing time, index> with comparator sorting by processing time first, index second in ascending order 5) While there are tasks to be processed AND min heap not empty, while time >= current task's enqueue time, enqueue next task. Then, if min heap is empty, then fast-forward time to the next task's enqueue time; else, get top of min heap, add task's processing time to time, and add task's index to result. 6) Return result typedef pair<int, int> T; struct compare { ....bool operator()(T& a, T&b) { ........// If processing time is equal, sort ........// by index in ascending order ........if (a.first == b.first) ............return a.second > b.second; ........// Sort processing time by ascending order ........return a.first > b.first; ....}.... }; class Solution { public: ....vector<int> getOrder(vector<vector<int>>& tasks) { ........vector<int> res; ........int n = tasks.size(); // number tasks ........ ........// Add index to each task ........for (int i = 0; i < n; i++) ............tasks[i].push_back(i); ........ ........// Sort tasks by enqueue time ........sort(tasks.begin(), tasks.end(), ............ [](vector<int> &a, vector<int> &b) { ............// If a and b have same enqueue time ............if (a[0] == b[0]) ................// Return ascending order by ................// shortest processing time ................return a[1] < b[1]; ............return a[0] < b[0]; ........}); ........ ........// Use min heap<processing time, index> to ........// prioritize tasks ........priority_queue<T, vector<T>, compare> pq; ........int i = 0; // task iterator ........long time = 0;........ ................ ........// While there are tasks queued in the min heap OR ........// there are still tasks that need to be processed ........while (!pq.empty() || i < n) { ............// While there are tasks that need to be ............// processed and the time elapsed >= enqueue time, ............// add task to min heap ............while (i < n && time >= tasks[i][0]) { ................pq.push({ tasks[i][1], tasks[i][2]}); ................i++; ............} ............ ............if (pq.empty()) { ................// If min heap is empty, then CPU is idle. Therefore, ................// fast-forward to the next task's enqueue time. ................time = (long)tasks[i][0]; ............} else { ................auto [procTime, idx] = pq.top(); ................pq.pop(); ................// Fast-forward time by task's processing time ................time += procTime; ................// Add index to result ................res.emplace_back(idx); ............} ........} ........ ........return res; ....} };

1014. Best Sightseeing Pair You are given an integer array values where values[i] represents the value of the ith sightseeing spot. Two sightseeing spots i and j have a distance j - i between them. The score of a pair (i < j) of sightseeing spots is values[i] + values[j] + i - j: the sum of the values of the sightseeing spots, minus the distance between them. Return the maximum score of a pair of sightseeing spots. Example 1: Input: values = [8,1,5,2,6] Output: 11 Explanation: i = 0, j = 2, values[i] + values[j] + i - j = 8 + 5 + 0 - 2 = 11 Example 2: Input: values = [1,2] Output: 2

Approach 1: One Pass Using Max Current and Previous Scores For each location j, calculate max score of j by tracking the max score of previous location i to calculate score of j. score = "values[i] + values[j] + i - j" = values[i] + values[j] + i - j = (values[i] + i) + (values[j] - j) class Solution { public: ....//........ i j ....// values = [8,1,5,2,6] ....// score = 8+5+0-2 = (8+0)+(5-2) = 11 ....int maxScoreSightseeingPair(vector<int>& values) { ........int res = 0; ........int n = values.size(); ........int best = 0; ........ ........// For each location j, calculate max score of j by ........// tracking the max score of previous location i to ........// calculate score of j. ........// ........// score = "values[i] + values[j] + i - j". ........// values[i] + values[j] + i - j = (values[i] + i) + (values[j] - j) ........// (values[i] + i) is the max best value that comes before j ........// since i < j. We need best value to maximize score. ........for (int i = 0; i < n; i++) { ............// Calculate j (max score of current location) ............res = max(res, best + values[i] - i); ............// Calculate i (max score among previous locations) ............best = max(best, values[i] + i); ........} ........ ........return res; ....} };

1828. Queries on Number of Points Inside a Circle You are given an array points where points[i] = [xi, yi] is the coordinates of the ith point on a 2D plane. Multiple points can have the same coordinates. You are also given an array queries where queries[j] = [xj, yj, rj] describes a circle centered at (xj, yj) with a radius of rj. For each query queries[j], compute the number of points inside the jth circle. Points on the border of the circle are considered inside. Return an array answer, where answer[j] is the answer to the jth query. Example 1: Input: points = [[1,3],[3,3],[5,3],[2,2]], queries = [[2,3,1],[4,3,1],[1,1,2]] Output: [3,2,2] Explanation: The points and circles are shown above. queries[0] is the green circle, queries[1] is the red circle, and queries[2] is the blue circle. Example 2: Input: points = [[1,1],[2,2],[3,3],[4,4],[5,5]], queries = [[1,2,2],[2,2,2],[4,3,2],[4,3,3]] Output: [2,3,2,4] Explanation: The points and circles are shown above. queries[0] is green, queries[1] is red, queries[2] is blue, and queries[3] is purple. Constraints: 1 <= points.length <= 500 points[i].length == 2 0 <= x​​​​​​i, y​​​​​​i <= 500 1 <= queries.length <= 500 queries[j].length == 3 0 <= xj, yj <= 500 1 <= rj <= 500 All coordinates are integers.

Approach 1: Pythagoreon Theorem class Solution { public: ....bool isInsideCircle(int cx, int cy, int r, int x, int y) { ........int x_diff = cx - x; ........int y_diff = cy - y; ........// Use pythagoreon theorem to calculate distance from ........// [x,y] to center [cx,cy]. If square difference of ........// distance is less than r^2, then point is in circle. ........return x_diff * x_diff + y_diff * y_diff <= r * r; ....} .... ....vector<int> countPoints(vector<vector<int>>& points, vector<vector<int>>& queries) { ........vector<int> res(queries.size(), 0); ........ ........for (int i = 0; i < queries.size(); i++) { ............for (int j = 0; j < points.size(); j++) { ................if (isInsideCircle(queries[i][0], queries[i][1], ................................ queries[i][2], ................................ points[j][0], points[j][1])) ....................res[i]++; ............} ........} ........ ........return res; ....} };

Excel Sheet Column Number Given a string columnTitle that represents the column title as appear in an Excel sheet, return its corresponding column number. For example: A -> 1 B -> 2 C -> 3 ... Z -> 26 AA -> 27 AB -> 28 ... Example 1: Input: columnTitle = "A" Output: 1 Example 2: Input: columnTitle = "AB" Output: 28 Example 3: Input: columnTitle = "ZY" Output: 701 Example 4: Input: columnTitle = "FXSHRXW" Output: 2147483647

Approach 1: Right to Left Scanning AZZC from right to left while accumulating results: First, ask the question, what the value of 'C' is: 'C' = 3 x 260 = 3 x 1 = 3 result = 0 + 3 = 3 Then, ask the question, what the value of 'Z*' is: 'Z*' = 26 x 261 = 26 x 26 = 676 result = 3 + 676 = 679 Then, ask the question, what the value of 'Z**' is: 'Z**' = 26 x 262 = 26 x 676 = 17576 result = 679 + 17576 = 18255 Finally, ask the question, what the value of 'A***' is: 'A***' = 1 x 263 = 1 x 17576 = 17576 result = 18255 + 17576 = 35831 class Solution { public: ....int titleToNumber(string columnTitle) { ........int num = 0; ........int len = columnTitle.length(); ........ ........for (int i = 0; i < len; i++) { ............int c = columnTitle[len - i - 1] - 'A' + 1; ............num += c * pow(26, i); ........} ........ ........return num; ....} };

713. Subarray Product Less Than K Given an array of integers nums and an integer k, return the number of contiguous subarrays where the product of all the elements in the subarray is strictly less than k. Example 1: Input: nums = [10,5,2,6], k = 100 Output: 8 Explanation: The 8 subarrays that have product less than 100 are: [10], [5], [2], [6], [10, 5], [5, 2], [2, 6], [5, 2, 6] Note that [10, 5, 2] is not included as the product of 100 is not strictly less than k. Example 2: Input: nums = [1,2,3], k = 0 Output: 0

Approach 1: Sliding Window /* nums = [10,5,2,6], k = 100 2,5,6,10 k=100 Match: - Two Pointers - Sliding Window Sol 1: 1) Init result=0 and product=1 variables 2) Init left=0, right=0. For right < nums.size(), add right value to sliding window by multiplying product *= nums[right], then remove the left value from the sliding window by dividing product /= nums[left] while product >= k, then update count as right - left + 1. 3) Return count */ class Solution { public: ....int numSubarrayProductLessThanK(vector<int>& nums, int k) { ........if (nums.size() <= 1) ............return 0; ........ ........int prod = 1; ........int count = 0; ........ ........for (int left = 0, right = 0; right < nums.size(); right++) { ............// Add right value to the sliding window ............prod *= nums[right]; ............ ............// If prod >= k, remove left value from the sliding window ............while (left <= right && prod >= k) ................prod /= nums[left++]; ............ ............// Update count ............count += right - left + 1; ........} ........ ........return count; ....} };

Longest Repeating Character Replacement You are given a string s and an integer k. You can choose any character of the string and change it to any other uppercase English character. You can perform this operation at most k times. Return the length of the longest substring containing the same letter you can get after performing the above operations. Example 1: Input: s = "ABAB", k = 2 Output: 4 Explanation: Replace the two 'A's with two 'B's or vice versa. Example 2: Input: s = "AABABBA", k = 1 Output: 4 Explanation: Replace the one 'A' in the middle with 'B' and form "AABBBBA". The substring "BBBB" has the longest repeating letters, which is 4. Constraints: 1 <= s.length <= 105 s consists of only uppercase English letters. 0 <= k <= s.length

Approach 1: Sliding Window + Hashmap + maxCharFreq #include <iostream> #include <vector> using namespace std; /* Sol 1: Sliding Window with Max Char Frequency 1) Init hashmap of 26 ints representing <char letter, int count> 2) Two conditions: 2a) Extend sliding window when (window length - most frequently occurring char in window < k char substitutions) by shifting the right ptr rightward 2b) Close sliding window when (window length - maxFreq > k) by shifting left ptr rightward 3) Return window length */ class Solution { public: ....int characterReplacement(string s, int k) { ........int len = 0, maxFreq = 0; ........ ........vector<int> count(26, 0); ........for (int i = 0; i < s.length(); ++i) { ............// Update the count of the most frequently occurring char ............maxFreq = max(maxFreq, ++count[s[i] - 'A']); ............ ............// If the window length - max frequency char < k char substitutions ............if (len - maxFreq < k) ................// Increase window length ................len++; ............else ................// Decrement char count of leftmost char in the window ................count[s[i - len] - 'A']--; ........} ........return len; ....} }; int main() { Solution s; cout << to_string(s.characterReplacement("AAAB", 1)) << endl; return 0; }

24. Swap Nodes in Pairs Given a linked list, swap every two adjacent nodes and return its head. You must solve the problem without modifying the values in the list's nodes (i.e., only nodes themselves may be changed.) Example 1: Input: head = [1,2,3,4] Output: [2,1,4,3] Example 2: Input: head = [] Output: [] Example 3: Input: head = [1] Output: [1]

Approach 1: Two Pointers 1) Init prev = prehead 2) While current and next node != NULL, swap the first and second nodes. Link previous first->next to current second node (first->next = second). 3) return prehead->next ListNode* swapPairs(ListNode* head) { ....ListNode *prehead = new ListNode(-1); ....prehead->next = head; ....ListNode *prev = prehead; .... ....while (head && head->next) { .... ListNode *first = head; .... ListNode *second = head->next; .... .... // Swap .... prev->next = second; .... first->next = second->next; .... second->next = first; .... .... // Setup next iteration .... prev = first; .... head = first->next; ....} ....return prehead->next; }

61. Rotate List Given the head of a linked list, rotate the list to the right by k places. Example 1: Input: head = [1,2,3,4,5], k = 2 Output: [4,5,1,2,3] Example 2: Input: head = [0,1,2], k = 4 Output: [2,0,1]

Approach 1: Update Head/Tail in Circular List 1) Make list circular 2) Find new tail at N-k and new head 3) Set new tail point to NULL 4) Set head ptr to new head Time: O(N) Space: O(1) class Solution { public:.... ....ListNode* rotateRight(ListNode* head, int k) { ........if (!head) ............return NULL; ........ ........ListNode *curr = head; ........int len = 1; ........ ........// Find end of list ........while (curr && curr->next) { ............len++; ............curr = curr->next; ........} ........ ........k %= len; ........ ........// Make list circular ........curr->next = head; ........ ........// Find new tail at len - k ........while (len-- > k) ............curr = curr->next; ........ ........// Set new head and tail ........head = curr->next; ........curr->next = NULL; ........ ........return head; ....} };

Evaluate Reverse Polish Notation Evaluate the value of an arithmetic expression in Reverse Polish Notation. Valid operators are +, -, *, and /. Each operand may be an integer or another expression. Note that division between two integers should truncate toward zero. It is guaranteed that the given RPN expression is always valid. That means the expression would always evaluate to a result, and there will not be any division by zero operation. Example 1: Input: tokens = ["2","1","+","3","*"] Output: 9 Explanation: ((2 + 1) * 3) = 9

Approach 2: Evaluate with Stack Create a stack that tracks the order of numbers to be processed in RPN. If a number, push to the stack. If an operator, pop the top 2 numbers, calculate the result, and push the result back on the stack. After looping through all strings, the solution is the top of the stack. Time: O(n) Space: O(n) class Solution { .... public: ....int evalRPN(vector<string>& tokens) { ........if (!tokens.size()) ............return 0; ........ ........stack<int> st; ........int result = 0; ........ ........for (string s : tokens) { ............int num1, num2; ............ ............if (!s.empty() && isdigit(s[0])) { ................st.push(stoi(s)); ............} else { ................int num1, num2; ................ ................num1 = st.top(); ................st.pop(); ................num2 = st.top(); ................st.pop(); ................ ................switch (s[0]) { ....................case '+': ........................result += num1 + num2; ........................break; ....................case '-': ........................result += num1 - num2; ........................break; ....................case '*': ........................result += num1 * num2; ........................break; ....................case '/': ........................result += num1 / num2; ........................break; ................} ............} ........} ........ ........return result; ....} };

61. Rotate List Given the head of a linked list, rotate the list to the right by k places. Example 1: Input: head = [1,2,3,4,5], k = 2 Output: [4,5,1,2,3] Example 2: Input: head = [0,1,2], k = 4 Output: [2,0,1]

Approach: Circular List Find length of the list and link tail to head. Then, traverse through the circular list by length - k nodes to find the new tail node. Update head and tail. class Solution { public: ....ListNode* rotateRight(ListNode* head, int k) { ........if (!head) ............return NULL; ........ ........int len = 1; ........ListNode *newHead = head, *tail = head; ........ ........// Get length of list and tail ........while (tail && tail->next) { ............len++; ............tail = tail->next; ........} ........ ........k %= len; ........ ........// Make list circular ........tail->next = head; ........ ........// Find new tail node residing at len-k ........for (int i = 0; i < len - k; i++) ............tail = tail->next; ........ ........// Update head and tail ........newHead = tail->next; ........tail->next = NULL; ........ ........return newHead; ....} };

Permutations Given an array nums of distinct integers, return all the possible permutations. You can return the answer in any order. Example 1: Input: nums = [1,2,3] Output: [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]

Backtracking (1) Choices: Create a decision tree for all the permutations of nums. Note how the indexes for nums changes for each permutation. Note that we need to swap 2 numbers when creating a new permutation, so we need 2 pointers to the nums array. Therefore, we need 2 pointers - (1) first ptr is the start of the for loop, and (2) i is the iterator in the for loop. (2) Constraints After choosing a value from nums, you can only choose among the remaining nums values. (3) Goal When have we reached our goal in creating a permutation? When first == nums.length(). class Solution { public: ....vector<vector<int>> permute(vector<int>& nums) { ........vector<vector<int>> result;........ ........if (!nums.size()) return result;........ ........backtrack(nums, result, 0);........ ........return result; ....} .... ....void backtrack(vector<int> nums, ................ vector<vector<int>>& result, ................ int first) { ........if (first == nums.size()) { ............result.push_back(nums); ............return; ........} ........ ........for (int i = first; i < nums.size(); i++) { ............if (first != i) ................swap(nums[first], nums[i]); ............ ............backtrack(nums, result, first + 1); ........} ....} };

Word Search Given an m x n grid of characters board and a string word, return true if word exists in the grid. The word can be constructed from letters of sequentially adjacent cells, where adjacent cells are horizontally or vertically neighboring. The same letter cell may not be used more than once. Input: board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCCED" Output: true

Backtracking Find the first character in the board. Then, use backtracking to find the rest of the characters. If the iterator i == word.length, then we found all of the matching chars. If x or y is out of bounds or does not match the current word[i], then return false. Then, increment i, temporarily mark the current board[x][y] as 0 so that you don't explore this same char, and explore dfs(x /- 1, y), dfs(x, y +/- 1). class Solution { private: ....vector<vector<char>> brd; ....string wrd; .... public: ....bool exist(vector<vector<char>>& board, string word) { ........brd = board; ........wrd = word; ........for (int x = 0; x < board.size(); x++) { ............for (int y = 0; y < board[x].size(); y++) { ................if (board[x][y] == word[0] && dfs(x, y, 0)) { ....................return true; ................} ............} ........} ........ ........return false; ....} .... ....bool dfs(int x, int y, int i) { ........if (i >= wrd.length()) ............return true; ........ ........if (x < 0 || x >= brd.size() || ............y < 0 || y >= brd[x].size() || ............brd[x][y] != wrd[i]) ............return false; ........ ........i++; ........char c = brd[x][y]; ........brd[x][y] = 0; ........bool found = dfs(x + 1, y, i) || ............dfs(x - 1, y, i) || ............dfs(x, y + 1, i) || ............dfs(x, y - 1, i); ........brd[x][y] = c; ........return found; ....} };

Letter Combinations of a Phone Number Given a string containing digits from 2-9 inclusive, return all possible letter combinations that the number could represent. Return the answer in any order. A mapping of digit to letters (just like on the telephone buttons) is given below. Note that 1 does not map to any letters. Input: digits = "23" Output: ["ad","ae","af","bd","be","bf","cd","ce","cf"]

Backtracking Let's break down the problem, by starting with an input that is only 1-digit long, for example digits = "2". This example is trivial - just generate all letters that correspond with digit = "2", which would be ["a", "b", "c"]. What if instead we had a 2-digit long input, digits = "23"? Imagine taking each letter of digit = "2" as a starting point. That is, lock the first letter in, and solve all the possible combinations that start with that letter. As you can see, solving the 1-digit case is trivial, and solving the 2-digit case is just solving the 1-digit case twice. The same reasoning can be extended to n digits. class Solution { private: ....map<char, string> mapping; .... public: ....Solution() : mapping{ ............{'2', {"abc"}}, ............{'3', {"def"}}, ............{'4', {"ghi"}}, ............{'5', {"jkl"}}, ............{'6', {"mno"}}, ............{'7', {"pqrs"}}, ............{'8', {"tuv"}}, ............{'9', {"wxyz"}}, ........} {} .... ....vector<string> letterCombinations(string digits) { ........vector<string> result; ........ ........if (digits.empty() || !digits.length()) ............return result; ........ ........letterCombosRec(digits, result, "", 0); ........ ........return result; ....} .... ....void letterCombosRec(string digits, vector<string>& result, string current, int i) {........ ........if (i == digits.length()) { ............result.push_back(current); ............return; ........} ........ ........string letters = mapping[digits[i]]; ........for (char c : letters) ............letterCombosRec(digits, result, current + c, i + 1); ........ ........return; ....} };

Subsets Given an integer array nums of unique elements, return all possible subsets (the power set). The solution set must not contain duplicate subsets. Return the solution in any order. Input: nums = [1,2,3] Output: [[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]

Backtracking (1) Choices (2) Constraints (3) Goal Every iteration add to result class Solution { public: ....vector<vector<int>> subsets(vector<int>& nums) { ........vector<vector<int>> result; ........if (!nums.size()) return result; ........backtrack(nums, result, vector<int>(), 0); ........return result; ....} .... ....void backtrack(vector<int>& nums, vector<vector<int>>& result, vector<int> current, int first) { ........result.push_back(current); ........for (int i = first; i < nums.size(); i++) { ............current.push_back(nums[i]); ............backtrack(nums, result, current, i + 1); ............current.pop_back(); ........} ....} };

Generate Parentheses Given n pairs of parentheses, write a function to generate all combinations of well-formed parentheses. Input: n = 3 Output: ["((()))","(()())","(())()","()(())","()()()"]

Backtracking Create recursive function that passes in output result, current string, int open, int close, and max=n. Base case is when current_string.length == 2*max. Decision section will add '(' only when open < max, and add ')' only when close < open. class Solution { public: ....vector<string> generateParenthesis(int n) { ........vector<string> result;........ ........if (!n) ............return result;........ ........genParenPermutations(result, "", 0, 0, n);........ ........return result; ....} .... ....void genParenPermutations(vector<string>& result, string current, ............................ int open, int close, int max) { ........if (current.length() == 2*max) { ............result.push_back(current); ............return; ........} ........ ........if (open < max) ............genParenPermutations(result, current + '(', open + 1, close, max); ........if (close < open) ............genParenPermutations(result, current + ')', open, close + 1, max); ....} };

Jump Game You are given an integer array nums. You are initially positioned at the array's first index, and each element in the array represents your maximum jump length at that position. Return true if you can reach the last index, or false otherwise. Example 1: Input: nums = [2,3,1,1,4] Output: true Explanation: Jump 1 step from index 0 to 1, then 3 steps to the last index.

Backtracking O(2^N). Try all possible values but results in timeout if input size is large. class Solution { public: ....bool canJump(vector<int>& nums) { ........if (!nums.size()) ............return false; ........ ........return backtrack(nums, 0); ....} .... ....bool backtrack(vector<int>&nums, int pos) { ........if (pos >= nums.size() - 1) ............return true; ................ ........for (int i = pos + nums[pos]; i > pos; i--) { ............if (backtrack(nums, i)) ................return true; ........} ........ ........return false; ....} }; Backtracking + DP Add memoization table to the backtracking algorithm. Time Complexity: O(N^2). For every nums[i], we check the values up to nums[i] + i. Therefore, we iterate through up to N*N. Space: O(2N). N for recursion. N for memo table. class Solution { private: ....enum JumpResult { ........SUCCESS, ........FAIL, ........UNKNOWN, ....}; .... ....vector<JumpResult> memo; ....vector<int> nums; .... public:.... ....bool canJump(vector<int>& numList) { ........memo.resize(numList.size()); ........for (int b = 0; b < memo.size() - 1; b++) ............memo[b] = UNKNOWN; ........memo[memo.size() - 1] = SUCCESS; ........ ........nums = numList; ........ ........return backtrack(0); ....} .... ....bool backtrack(int pos) { ........if (memo[pos] != JumpResult::UNKNOWN) ............return memo[pos] == JumpResult::SUCCESS; ........ ........int maxJump = min(pos + nums[pos], (int)nums.size() - 1); ........for (int i = maxJump; i > pos; i--) { ............if (backtrack(i)) { ................memo[pos] = JumpResult::SUCCESS; ................return true; ............} ........} ........ ........memo[pos] = JumpResult::FAIL; ........return false; ....} }; Greedy Approach If you iterate backwards, then check if the current nums[i] + i can reach the last index that could reach the end. O(N). class Solution { public: ....bool canJump(vector<int>& nums) { ........int lastIndex = nums.size() - 1; ........for (int i = lastIndex; i >= 0; i--) { ............if (i + nums[i] >= lastIndex) ................lastIndex = i; ........} ........return lastIndex == 0; ....} };

Pow(x, n) Implement pow(x, n), which calculates x raised to the power n (i.e., xn). Example 1: Input: x = 2.00000, n = 10 Output: 1024.00000 Example 2: Input: x = 2.10000, n = 3 Output: 9.26100 Example 3: Input: x = 2.00000, n = -2 Output: 0.25000 Explanation: 2-2 = 1/22 = 1/4 = 0.25

Binary Search O(log n). Calculate the power by halving the power recursively. If the exponent is even, return half * half. If the exponent is odd, return half * half * x. class Solution { public: ....double helper(double x, int n) { ........if (n == 0) ............return 1; ........ ........double half = helper(x, n / 2); ........if (n % 2 == 0) ............return half * half; ........else return half * half * x; ....} .... ....double myPow(double x, int n) { ........long long N = n; ........ ........if (N < 0) { ............N = -N; ............x = 1/x; ........} ........ ........return helper(x, n); ....} };

Sqrt(x) Given a non-negative integer x, compute and return the square root of x. Since the return type is an integer, the decimal digits are truncated, and only the integer part of the result is returned. Note: You are not allowed to use any built-in exponent function or operator, such as pow(x, 0.5) or x ** 0.5. Example 1: Input: x = 4 Output: 2 Example 2: Input: x = 8 Output: 2 Explanation: The square root of 8 is 2.82842..., and since the decimal part is truncated, 2 is returned.

Binary Search Since sqrt is base 2, we can use binary search to divide and conquer the result. Just use binary search but check mid^2 < x and mid^2 > x. Time: O(log n) Space: O(1) class Solution { public: ....int mySqrt(int x) { ........long long left = 0; ........long long right = x; ........ ........while (left <= right) { ............long long mid = left + (right - left)/2; ............ ............if (mid * mid < x) ................left = mid + 1; ............else if (mid * mid > x) ................right = mid - 1; ............else ................return (int)mid; ........} ........return (int)left - 1; ....} }; Newtons Method Newton's mathematical proof to compute sqrt. x_k+1 = 1/2 * (x_k + x / x_k) class Solution { public: ....int mySqrt(int x) { ........if (x < 2) ............return x; ........ ........double x0 = x; ........double x1 = (x0 + x / x0) / 2; ........ ........while (abs(x0 - x1) >= 1) { ............x0 = x1; ............x1 = (x0 + x / x0) / 2; ........} ........ ........return (int)x1; ....} }; Time: O(log n) Space: O(1)

Search for a Range Given an array of integers nums sorted in ascending order, find the starting and ending position of a given target value. If target is not found in the array, return [-1, -1]. You must write an algorithm with O(log n) runtime complexity. Example 1: Input: nums = [5,7,7,8,8,10], target = 8 Output: [3,4]

Binary Search Use binary search to find to first and last element. When finding the start index, check nums[midpoint] >= target (not > target) so that you keep shifting left when nums[midpoint] == target. Likewise, check nums[midpoint] <= target (not < target) so that you keep shifting right when nums[midpoint] == target. class Solution { public: ....vector<int> searchRange(vector<int>& nums, int target) { ........vector<int> result(2); ........result[0] = findRangeStart(nums, target, 0, nums.size() - 1); ........result[1] = findRangeEnd(nums, target, result[0], nums.size() - 1); ........return result; ....} .... ....int findRangeStart(vector<int>& nums, int target, int start, int end) { ........int i = -1; ................ ........while (start <= end) { ............int midpoint = start + (end - start)/2; ............ ............if (nums[midpoint] >= target) { ................end = midpoint - 1; ................ ................if (nums[midpoint] == target) ....................i = midpoint; ............} else { ................start = midpoint + 1; ............} ........} ........ ........return i; ....} .... ....int findRangeEnd(vector<int>& nums, int target, int start, int end) { ........int i = -1; ........ ........if (start < 0) ............return start; ........ ........while (start <= end) { ............int midpoint = start + (end - start)/2; ............ ............if (nums[midpoint] <= target) { ................start = midpoint + 1; ................ ................if (nums[midpoint] == target) ....................i = midpoint; ............} else { ................end = midpoint - 1; ............} ........} ........ ........return i; ....} };

Design Tic-Tac-Toe Assume the following rules are for the tic-tac-toe game on an n x n board between two players: A move is guaranteed to be valid and is placed on an empty block. Once a winning condition is reached, no more moves are allowed. A player who succeeds in placing n of their marks in a horizontal, vertical, or diagonal row wins the game. Implement the TicTacToe class: TicTacToe(int n) Initializes the object the size of the board n. int move(int row, int col, int player) Indicates that the player with id player plays at the cell (row, col) of the board. The move is guaranteed to be a valid move. Example 1: Input ["TicTacToe", "move", "move", "move", "move", "move", "move", "move"] [[3], [0, 0, 1], [0, 2, 2], [2, 2, 1], [1, 1, 2], [2, 0, 1], [1, 0, 2], [2, 1, 1]] Output [null, 0, 0, 0, 0, 0, 0, 1]

Brute Force For each move, track the number of player moves are in the current row, column, diagonal, and anti-diagonal. Note that a move only counts as diagonal/antidiagonal if col == row or col == (N - row - 1). Track Row/Col/Diagonal/Anti-diagonal Count Rather than tracking player moves using a board object, track the count of moves for each row/column/diagonal/antidiagonal. If both players have made a move in the same row/col/etc, then the count for that row/col/etc cannot equal N. If count for that row/col/etc equals N, then declare winner. class TicTacToe { private: ....vector<int> rowCount, colCount; ....int diagCount, antidiagCount; ....int winner; ....int N; .... public: ....TicTacToe(int n) { ........// 0: no one won ........// 1: player1 won ........// 2: player2 won ........winner = 0; ........N = n; ........rowCount = vector<int>(n, 0); ........colCount = vector<int>(n, 0); ........diagCount = antidiagCount = 0; ....} .... ....int move(int row, int col, int player) { ........int currPlayer = player == 1 ? 1 : -1; ........ ........if (row < 0 || row >= N || ............col < 0 || col >= N) ............return 0; ........ ........if (winner) ............return winner; ........ ........rowCount[row] += currPlayer; ........colCount[col] += currPlayer; ........ ........if (row == col) ............diagCount += currPlayer; ........ ........if (col == (N - row - 1)) ............antidiagCount += currPlayer; ........ ........if (abs(rowCount[row]) == N || ............abs(colCount[col]) == N || ............abs(diagCount) == N || ............abs(antidiagCount) == N) { ............winner = player; ............return player; ........} ........ ........return 0; ....} };

Find the Celebrity Suppose you are at a party with n people (labeled from 0 to n - 1), and among them, there may exist one celebrity. The definition of a celebrity is that all the other n - 1 people know him/her, but he/she does not know any of them. Now you want to find out who the celebrity is or verify that there is not one. The only thing you are allowed to do is to ask questions like: "Hi, A. Do you know B?" to get information about whether A knows B. You need to find out the celebrity (or verify there is not one) by asking as few questions as possible (in the asymptotic sense). You are given a helper function bool knows(a, b) which tells you whether A knows B. Implement a function int findCelebrity(n). There will be exactly one celebrity if he/she is in the party. Return the celebrity's label if there is a celebrity in the party. If there is no celebrity, return -1. Example 1: Input: graph = [[1,1,0],[0,1,0],[1,1,1]] Output: 1 Explanation: There are three persons labeled with 0, 1 and 2. graph[i][j] = 1 means person i knows person j, otherwise graph[i][j] = 0 means person i does not know person j. The celebrity is the person labeled as 1 because both 0 and 2 know him but 1 does not know anybody. Example 2: Input: graph = [[1,0,1],[1,1,0],[0,1,1]] Output: -1 Explanation: There is no celebrity.

Brute Force For each person, check if they know someone else and if someone else knows them. class Solution { public: ....int findCelebrity(int n) { ........for (int i = 0; i < n; i++) { ............bool isCeleb = true; ............for (int j = 0; j < n; j++) { ................// If i != j (not the same person) && ................// i knows j (if i knows someone, they i ................//.... cannot be a celeb since the celeb ................//.... knows no one else) && ................// j does not know i (if j does not know i, ................//.... then i cannot be a celeb since ................//.... everyone should know a celeb) ................if (i != j && (knows(i, j) || !knows(j, i))) { ....................isCeleb = false; ....................break; ................} ............} ............if (isCeleb) ................return i; ........} ........ ........return -1; ....} }; Approach 2: Logical Deduction The following algorithm can, therefore, be used to rule out n - 1 of the people in O(n) time. We start by guessing that 0 might be a celebrityCandidate, and then we check if 0 knows 1 (within the loop). If true, then we know 0 isn't a celebrity (they know somebody), but 1 might be. We update the celebrityCandidate variable to 1 to reflect this. Otherwise, we know 1 is not a celebrity (somebody doesn't know them), but we haven't ruled out 0, yet, so keep them as the celebrityCandidate. Whoever we kept is then asked if they know 2, and so forth. But do we actually know for sure that this person is a celebrity? (Remember, it's possible there's no celebrity, in which case we'd return -1). Nope! It's still possible that 0 doesn't know 4, or perhaps 4 knows 3. We can't rule these possibilities out from the information we have uncovered so far. So, what can we do? We can use our isCelebrity(...) function on 4 to check whether or not they are a celebrity. If they are, our function will return 4. If not, then it should return -1. Time: O(n) Space: O(1) class Solution { private: ....int N; .... public: ....int findCelebrity(int n) { ........int candidate = 0; ........N = n; ........ ........for (int i = 0; i < n; i++) { ............// If candiate knows i, then candidate is ............// not a celeb but i might be a celeb, ............// so set candidate=i. ............// If candidate does not know i, then ............// candidate might be a celeb. Continue ............// to check. ............if (knows(candidate, i)) ................candidate = i; ........} ........ ........if (isCeleb(candidate)) ............return candidate; ........ ........return -1; ....} .... ....int isCeleb(int candidate) { ........for (int j = 0; j < N; j++) { ............// If candidate and j are the same person, skip ............if (candidate == j) continue; ............// If candidate knows j, they cannnot be a candidate ............// If j does not know candidate, they cannot be a candidate ............if (knows(candidate, j) || !knows(j, candidate)) ................return false; ........} ........return true; ....} };

Divide Two Integers Given two integers dividend and divisor, divide two integers without using multiplication, division, and mod operator. Return the quotient after dividing dividend by divisor. The integer division should truncate toward zero, which means losing its fractional part. For example, truncate(8.345) = 8 and truncate(-2.7335) = -2. Note: Assume we are dealing with an environment that could only store integers within the 32-bit signed integer range: [−231, 231 − 1]. For this problem, assume that your function returns 231 − 1 when the division result overflows. Example 1: Input: dividend = 10, divisor = 3 Output: 3 Explanation: 10/3 = truncate(3.33333..) = 3.

Brute Force Subtract divisor from dividend and keep incrementing quotient. Time: O(n) Space: O(1) class Solution { public: ....int divide(int dividend, int divisor) { ........int quotient = 0; ........bool negative = (dividend < 0) ^ (divisor < 0); ........ ........while (dividend >= divisor) { ............dividend -= divisor; ............quotient++; ........} ........ ........return negative ? -quotient : quotient; ....} }; Speed up Division Using Accumulator Time: O(log n) Space: O(1) class Solution { public: ....int divide(int dividend, int divisor) { ........if (dividend == INT_MIN && divisor == -1) ............return INT_MAX; ........if (dividend == INT_MIN && divisor == 1) ............return INT_MIN; ........ ........int quotient = 0; ........bool negative = (dividend < 0) ^ (divisor < 0); ........ ........// INT_MIN = 2^31 and INT_MAX = 2^31-1 ........// INT_MIN has 1 more number than INT_MAX, so use ........// negative int range to calculate quotient ........// and prevent int overflow ........if (dividend > 0) dividend = -dividend; ........if (divisor > 0) divisor = -divisor; ........ ........int accum = divisor; ........int i = 1; ........ ........// Find out max multiple of divisor less than dividend ........// accum >= INT_MIN>>1: Check that accum+accum won't overflow ........// ex: 2 >= -1073741824 ........while (accum >= INT_MIN>>1 && dividend <= (accum+accum)) { ............accum += accum; ............i += i; ........} ........ ........// Calculate quotient by subtracting dividend - accum, ........// and then halving accum and i. ........while (dividend <= divisor) { ............if (dividend <= accum) { ................dividend -= accum; ................quotient += i; ............} ............ ............accum >>= 1; ............i >>= 1; ........} ........ ........return negative ? -quotient : quotient; ....} };

Increasing Triplet Subsequence Given an integer array nums, return true if there exists a triple of indices (i, j, k) such that i < j < k and nums[i] < nums[j] < nums[k]. If no such indices exists, return false. Input: nums = [2,1,5,0,4,6] Output: true Explanation: The triplet (3, 4, 5) is valid because nums[3] == 0 < nums[4] == 4 < nums[5] == 6.

Brute Force 3 for loops while checking nums[i] < nums[j] < nums[k]. O(N^3). Linear Scan Create 2 variables to store nums[i] and nums[j]. Loop through nums and - if i < num1, set num1; if num1 < i < num2, set num2; else i > num2, return true. class Solution { public: ....bool increasingTriplet(vector<int>& nums) { ........int num1 = INT_MAX; ........int num2 = INT_MAX; ........ ........for (int i : nums) { ............if (i < num1) ................num1 = i; ............else if (num1 < i && i < num2) ................num2 = i; ............else if (i > num2) ................return true; ........} ........ ........return false; ....} };

Missing Ranges You are given an inclusive range [lower, upper] and a sorted unique integer array nums, where all elements are in the inclusive range. A number x is considered missing if x is in the range [lower, upper] and x is not in nums. Return the smallest sorted list of ranges that cover every missing number exactly. That is, no element of nums is in any of the ranges, and each missing number is in one of the ranges. Each range [a,b] in the list should be output as: "a->b" if a != b "a" if a == b Input: nums = [0,1,3,50,75], lower = 0, upper = 99 Output: ["2","4->49","51->74","76->99"] Explanation: The ranges are: [2,2] --> "2" [4,49] --> "4->49" [51,74] --> "51->74" [76,99] --> "76->99"

Brute Force Loop from lower to upper, adding to the result vector<string> if it's missing a range. Linear Scan Loop through nums to determine the missing ranges. class Solution { public: ....string formatRange(int lo, int hi) { ........if (lo == hi) ............return to_string(lo); ........else ............return to_string(lo) + "->" + to_string(hi); ....} .... ....vector<string> findMissingRanges(vector<int>& nums, int lower, int upper) { ........vector<string> result; ........ ........if (!nums.size()) ............return vector<string>{ formatRange(lower, upper) }; ........ ........for (int i = 0; i <= nums.size(); i++) { ............if (i == 0 && lower < nums[i]) ................result.push_back(formatRange(lower, nums[i] - 1)); ............else if (i == nums.size() && nums[i-1] < upper) ................result.push_back(formatRange(nums[i-1] + 1, upper)); ............else if (i > 0 && i < nums.size() && nums[i-1] != (nums[i] - 1)) ................result.push_back(formatRange(nums[i-1] + 1, nums[i] - 1)); ........} ........ ........return result; ....} };

Odd Even Linked List Given the head of a singly linked list, group all the nodes with odd indices together followed by the nodes with even indices, and return the reordered list. The first node is considered odd, and the second node is even, and so on. Note that the relative order inside both the even and odd groups should remain as it was in the input. You must solve the problem in O(1) extra space complexity and O(n) time complexity.

Create 3 ptrs: odd = head, even = head->next, evenHead = even. Loop through the list, adding the odd nodes to the odd list and even nodes to the even list. After the loop, link the even and odd lists via odd->next = evenHead. class Solution { public: ....ListNode* oddEvenList(ListNode* head) { ........if (!head) ............return NULL; ........ ........ListNode *odd = head; ........ListNode *even = head->next; ........ListNode *evenHead = even; ........ ........while (even && even->next) { ............odd->next = even->next; ............odd = odd ? odd->next : odd; ............even->next = odd->next; ............even = even ? even->next : even; ........} ........odd->next = evenHead; ........ ........return head; ....} };

Longest Substring Without Repeating Characters Given a string s, find the length of the longest substring without repeating characters. Input: s = "abcabcbb" Output: 3 Explanation: The answer is "abc", with the length of 3.

Create hashmap that stores the char and (latest index of current char + 1). Iterate through the string with a fast and slow ptr. Calculate the difference between "fast - slow + 1" and set max length to max(length, fast - slow + 1). Update map[char] = j + 1, representing the next char after the current character so that, if we get a duplicate char, then we set it to the next char after the previous index of that char. class Solution { public: ....int lengthOfLongestSubstring(string s) { ........int len = 0; ........unordered_map<char, int> map; ........ ........for (int i = 0, j = 0; j < s.length(); j++) { ............if (map.find(s[j]) != map.end()) ................i = max(map[s[j]], i); ............ ............map[s[j]] = j + 1; ............len = max(len, j - i + 1); ........} ........ ........return len; ....} };

Serialize and Deserialize Binary Tree Serialization is the process of converting a data structure or object into a sequence of bits so that it can be stored in a file or memory buffer, or transmitted across a network connection link to be reconstructed later in the same or another computer environment. Design an algorithm to serialize and deserialize a binary tree. There is no restriction on how your serialization/deserialization algorithm should work. You just need to ensure that a binary tree can be serialized to a string and this string can be deserialized to the original tree structure. Clarification: The input/output format is the same as how LeetCode serializes a binary tree. You do not necessarily need to follow this format, so please be creative and come up with different approaches yourself. Example 1: Input: root = [1,2,3,null,null,4,5] Output: [1,2,3,null,null,4,5]

DFS Serialize by converting to a string using preorder DFS. Convert from int to string using to_string. Deserialize by building the tree in preorder. When building the tree, tokenize/split the string using stringstream/getline. Convert from string to int using stoi. class Codec { public:.... ....// Encodes a tree to a single string. ....string serialize(TreeNode* root) { ........if (root == NULL) ............return ""; ........ ........return to_string(root->val) + "," + ............ serialize(root->left) + "," + ............ serialize(root->right); ....} .... ....TreeNode* createTree(stringstream &ss) { ........string token; ........getline(ss, token, ','); ........ ........if (token == "") ............return NULL; ........ ........TreeNode* node = new TreeNode(stoi(token)); ........node->left = createTree(ss); ........node->right = createTree(ss); ........return node; ....} ....// Decodes your encoded data to tree. ....TreeNode* deserialize(string data) { ........stringstream ss(data); ........return createTree(ss); ....} };

Number of Islands Given an m x n 2D binary grid grid which represents a map of '1's (land) and '0's (water), return the number of islands. An island is surrounded by water and is formed by connecting adjacent lands horizontally or vertically. You may assume all four edges of the grid are all surrounded by water. Input: grid = [ ["1","1","0","0","0"], ["1","1","0","0","0"], ["0","0","1","0","0"], ["0","0","0","1","1"] ] Output: 3

DFS Recursion Iterate through the grid and, if grid[i][j] == '1', then flip that char to '0' and every bordering '1' to '0' using DFS recursion. class Solution { public: ....int numIslands(vector<vector<char>>& grid) { ........if (!grid.size() || !grid[0].size()) ............return 0; ........ ........int numIslands = 0; ........ ........for (int i = 0; i < grid.size(); i++) { ............for (int j = 0; j < grid[i].size(); j++) { ................if (grid[i][j] == '1') { ....................numIslands++; ....................dfs(grid, i, j); ................} ............} ........} ........ ........return numIslands; ....} .... ....void dfs(vector<vector<char>>& grid, int i, int j) { ........if (i < 0 || i >= grid.size() || ............j < 0 || j >= grid[i].size() || ............grid[i][j] == '0') ............return; ........ ........grid[i][j] = '0'; ........dfs(grid, i + 1, j); ........dfs(grid, i - 1, j); ........dfs(grid, i, j + 1); ........dfs(grid, i, j - 1); ....} }; BFS Iteration class Solution { public: ....int numIslands(vector<vector<char>>& grid) { ........if (!grid.size() || !grid[0].size()) ............return 0; ........ ........int numIslands = 0; ........ ........for (int i = 0; i < grid.size(); i++) { ............for (int j = 0; j < grid[i].size(); j++) { ................if (grid[i][j] == '1') { ....................numIslands++; ....................grid[i][j] = '0'; .................... ....................queue<pair<int, int>> q; ....................q.push({i, j}); .................... ....................while (!q.empty()) { ........................auto p = q.front(); ........................q.pop(); ........................ ........................int x = p.first; ........................int y = p.second; ................................................ ........................if ((x + 1) >= 0 && (x + 1) < grid.size() && grid[x+1][y] == '1') { ............................q.push({x + 1, y}); ............................grid[x+1][y] = '0'; ........................} ........................ ........................if ((x - 1) >= 0 && (x - 1) < grid.size() && grid[x-1][y] == '1') { ............................q.push({x - 1, y}); ............................grid[x-1][y] = '0'; ........................} ........................ ........................if ((y + 1) >= 0 && (y + 1) < grid[x].size() && grid[x][y+1] == '1') { ............................q.push({x, y + 1}); ............................grid[x][y+1] = '0'; ........................} ........................ ........................if ((y - 1) >= 0 && (y - 1) < grid[x].size() && grid[x][y-1] == '1') { ............................q.push({x, y - 1}); ............................grid[x][y-1] = '0'; ........................} ....................} ................} ............} ........} ........ ........return numIslands; ....} };

Unique Paths A robot is located at the top-left corner of a m x n grid (marked 'Start' in the diagram below). The robot can only move either down or right at any point in time. The robot is trying to reach the bottom-right corner of the grid (marked 'Finish' in the diagram below). How many possible unique paths are there? Example 1: Input: m = 3, n = 7 Output: 28 Example 2: Input: m = 3, n = 2 Output: 3 Explanation: From the top-left corner, there are a total of 3 ways to reach the bottom-right corner: 1. Right -> Down -> Down 2. Down -> Down -> Right 3. Down -> Right -> Down

Dynamic Programming Create a memoization table of size m*n. Memo table stores the number of paths to reach that location. Then, return the bottom-right value in the memo table. Time: O(N*M) Space: O(N*M) class Solution { public: ....int uniquePaths(int m, int n) { ........vector<vector<int>> pathCount(m, vector<int>(n, 1)); ........ ........for (int r = 1; r < m; r++) { ............for (int c = 1; c < n; c++) { ................pathCount[r][c] = pathCount[r-1][c] + pathCount[r][c-1]; ............} ........} ........ ........return pathCount[m-1][n-1]; ....} }; Recursive Approach O(2^N). Not time efficient. class Solution { public: ....int uniquePaths(int m, int n) { ........if (m == 1 || n == 1) ............return 1; ........return uniquePaths(m - 1, n) + uniquePaths(m, n - 1); ....} };

Longest Increasing Subsequence Given an integer array nums, return the length of the longest strictly increasing subsequence. A subsequence is a sequence that can be derived from an array by deleting some or no elements without changing the order of the remaining elements. For example, [3,6,2,7] is a subsequence of the array [0,3,1,6,2,2,7]. Example 1: Input: nums = [10,9,2,5,3,7,101,18] Output: 4 Explanation: The longest increasing subsequence is [2,3,7,101], therefore the length is 4. Example 2: Input: nums = [0,1,0,3,2,3] Output: 4

Dynamic Programming The goal is to find the length of the longest increasing subsequence. Therefore, create a memoization array storing the longest subsequence length at each index of nums. For each position, we need 2 ptrs - 1 ptr j to iterate through nums, 1 ptr i to iterate through each previous value up to the current nums index j. For each index, store the max subsequence length. Then, return the max subsequence length. Realizing a Dynamic Programming Problem This problem has two important attributes that let us know it should be solved by dynamic programming. First, the question is asking for the maximum or minimum of something. Second, we have to make decisions that may depend on previously made decisions, which is very typical of a problem involving subsequences. Framework to solve DP Problems (1) DP array representing solutions to subproblems (2) Recurrence Relation (a way to transition between states, such as dp[5] and dp[7]) (3) Base Case (For this problem, we can initialize every element of dp to 1, since every element on its own is technically an increasing subsequence.) class Solution { public: ....int lengthOfLIS(vector<int>& nums) { ........int len = nums.size(); ........vector<int> memo(len, 1); ........int count = 0; ........ ........if (len < 2) ............return nums.size(); ........ ........for (int j = 1; j < len; j++) { ............for (int i = 0; i < j; i++) { ................if (nums[j] > nums[i]) { ....................memo[j] = max(memo[j], memo[i] + 1); ................} ............} ............count = max(memo[j], count); ........} ........ ........return count; ....} };

Coin Change You are given an integer array coins representing coins of different denominations and an integer amount representing a total amount of money. Return the fewest number of coins that you need to make up that amount. If that amount of money cannot be made up by any combination of the coins, return -1. You may assume that you have an infinite number of each kind of coin. Example 1: Input: coins = [1,2,5], amount = 11 Output: 3 Explanation: 11 = 5 + 5 + 1 Example 2: Input: coins = [2], amount = 3 Output: -1

Dynamic Programming We want to determine the fewest number of coins that total an amount. Therefore, create a memoization array that stores the min coins that total each amount from 0 to amount. Time: O(S*N) where S = coins.size and N = amount Space: O(S) where S = coins.size class Solution { public: ....int coinChange(vector<int>& coins, int amount) { ........// Init memo to the max amount possible (amount + 1). ........// MAX_INT can be used alternatively to amount + 1. ........// Each index represents the min coins to sum that index. ........vector<int> memo(amount + 1, amount + 1); ........memo[0] = 0; ........ ........// Calculate the min coins to sum to memo[m] ........// dp[0] = 0 (amount=0 requires 0 coins) ........for (int m = 1; m < memo.size(); m++) { ............// For each coin ............for (int c = 0; c < coins.size(); c++) { ................// If coin sum m >= current coin value, ................// then (sum m - coin value) >= 0, so we ................// possible found a soln. If ................// (sum m - coin value) < 0, then no soln. ................if (m >= coins[c]) { ....................// Recurrence Relation - ....................// Set memo as the minimum bet/ not taking the ....................// current coin and taking the current coin ....................// 1 + memo[remaining - coin value]. ....................// +1 represents current count. ....................// ex. coin[c]=4, m=7 ....................// memo[7] = min(memo[7], memo[7-4=3] + 1) ....................memo[m] = min(memo[m], memo[m - coins[c]] + 1); ................} ............} ........} ........ ........// If the memo amount > max amount possible, ........// then -1 since no solution possible; ........// else, return memo amount ........return memo[amount] >= (amount + 1) ? -1 : memo[amount]; ....} };

Factorial Trailing Zeroes Given an integer n, return the number of trailing zeroes in n!. Note that n! = n * (n - 1) * (n - 2) * ... * 3 * 2 * 1. Example 1: Input: n = 3 Output: 0 Explanation: 3! = 6, no trailing zero. Example 2: Input: n = 5 Output: 1 Explanation: 5! = 120, one trailing zero. Example 3: Input: n = 0 Output: 0

Factors of 5 The idea is: (1) The ZERO comes from 10. (2) The 10 comes from 2 x 5 (3) And we need to account for all the products of 5 and 2. likes 4×5 = 20 ... (4) So, if we take all the numbers with 5 as a factor, we'll have way more than enough even numbers to pair with them to get factors of 10 Example One How many multiples of 5 are between 1 and 23? There is 5, 10, 15, and 20, for four multiples of 5. Paired with 2's from the even factors, this makes for four factors of 10, so: 23! has 4 zeros. Example Two How many multiples of 5 are there in the numbers from 1 to 100? because 100 ÷ 5 = 20, so, there are twenty multiples of 5 between 1 and 100. but wait, actually 25 is 5×5, so each multiple of 25 has an extra factor of 5, e.g. 25 × 4 = 100,which introduces extra of zero. So, we need know how many multiples of 25 are between 1 and 100? Since 100 ÷ 25 = 4, there are four multiples of 25 between 1 and 100. Finally, we get 20 + 4 = 24 trailing zeroes in 100! The above example tell us, we need care about 5, 5×5, 5×5×5, 5×5×5×5 .... Example Three By given number 4617. 5^1 : 4617 ÷ 5 = 923.4, so we get 923 factors of 5 5^2 : 4617 ÷ 25 = 184.68, so we get 184 additional factors of 5 5^3 : 4617 ÷ 125 = 36.936, so we get 36 additional factors of 5 5^4 : 4617 ÷ 625 = 7.3872, so we get 7 additional factors of 5 5^5 : 4617 ÷ 3125 = 1.47744, so we get 1 more factor of 5 5^6 : 4617 ÷ 15625 = 0.295488, which is less than 1, so stop here. Then 4617! has 923 + 184 + 36 + 7 + 1 = 1151 trailing zeroes. class Solution { public: ....int trailingZeroes(int n) { ........int tmp = 0; ........int count = 0; ........ ........while (n/5 > 0) { ............tmp = n/5; ............count += tmp; ............n = tmp; ........} ........ ........return count; ....} }; Time complexity : O(log n). In this approach, we divide n by each power of 55. By definition, there are log_base5(n) powers of 5 less-than-or-equal-to n. Because the multiplications and divisions are within the 32-bit integer range, we treat these calculations as O(1). Space complexity : O(1).

Search in Rotated Sorted Array There is an integer array nums sorted in ascending order (with distinct values). Prior to being passed to your function, nums is possibly rotated at an unknown pivot index k (1 <= k < nums.length) such that the resulting array is [nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]] (0-indexed). For example, [0,1,2,4,5,6,7] might be rotated at pivot index 3 and become [4,5,6,7,0,1,2]. Given the array nums after the possible rotation and an integer target, return the index of target if it is in nums, or -1 if it is not in nums. You must write an algorithm with O(log n) runtime complexity. Example 1: Input: nums = [4,5,6,7,0,1,2], target = 0 Output: 4 Example 2: Input: nums = [4,5,6,7,0,1,2], target = 3 Output: -1

Find min and target (1) Find min value in nums using modified binary search (2) Set left and right bounds based on where the min value is (3) Binary search for target using left/right bounds class Solution { public: ....int search(vector<int>& nums, int target) { ........int left = 0; ........int right = nums.size() - 1; ........ ........while (left < right) { ............int mid = left + (right - left) / 2; ............if (nums[mid] > nums[right]) ................left = mid + 1; ............else ................right = mid; ........} ........ ........int start = left; ........int end = nums.size() - 1; ................ ........if (target >= nums[start] && ............target <= nums[end]) { ............right = end; ........} else { ............left = 0; ........} ........ ........while (left <= right) { ............int mid = left + (right - left)/2; ............if (nums[mid] < target) ................left = mid + 1; ............else if (nums[mid] > target) ................right = mid - 1; ............else ................return mid; ........} ........ ........return -1; ....} };

Insert Delete GetRandom O(1) Implement the RandomizedSet class: RandomizedSet() Initializes the RandomizedSet object. bool insert(int val) Inserts an item val into the set if not present. Returns true if the item was not present, false otherwise. bool remove(int val) Removes an item val from the set if present. Returns true if the item was present, false otherwise. int getRandom() Returns a random element from the current set of elements (it's guaranteed that at least one element exists when this method is called). Each element must have the same probability of being returned. You must implement the functions of the class such that each function works in average O(1) time complexity. Example 1: Input ["RandomizedSet", "insert", "remove", "insert", "getRandom", "remove", "insert", "getRandom"] [[], [1], [2], [2], [], [1], [2], []] Output [null, true, false, true, 2, true, false, 2]

Hash Map + Vector Create hash map with indexes to a vector of nums. Lookup for hash map is O(1). getRandom is O(1) using the vector. Removal requires swapping the current val with the back of the vector and swapping the hash map indexes pointing to the current val and last vector value. class RandomizedSet { private: ....unordered_map<int, int> mapping; ....vector<int> nums; .... public: ....RandomizedSet() { ........srand((unsigned)time(NULL)); ....} .... ....bool insert(int val) { ........if (mapping.find(val) != mapping.end()) ............return false; ........nums.push_back(val); ........mapping[val] = nums.size() - 1; ........return true; ....} .... ....bool remove(int val) { ........if (mapping.find(val) == mapping.end()) ............return false; ........int last = nums.back(); ........swap(nums[mapping[val]], nums[nums.size() - 1]); ........swap(mapping[val], mapping[last]); ........nums.pop_back(); ........mapping.erase(val); ........return true; ....} .... ....int getRandom() { ........return nums[rand() % nums.size()]; ....} };

Happy Number Write an algorithm to determine if a number n is happy. A happy number is a number defined by the following process: Starting with any positive integer, replace the number by the sum of the squares of its digits. Repeat the process until the number equals 1 (where it will stay), or it loops endlessly in a cycle which does not include 1. Those numbers for which this process ends in 1 are happy. Return true if n is a happy number, and false if not. Example 1: Input: n = 19 Output: true Explanation: 12 + 92 = 82 82 + 22 = 68 62 + 82 = 100 12 + 02 + 02 = 1 Example 2: Input: n = 2 Output: false

Hash Set Use hash set to track whether a sum of squares has already been calculated. Since we're calculating sums, Sum of squares should always be unique unless we approach a cycle. class Solution { private: ....unordered_map<int, int> hashset; .... public: ....bool isHappy(int n) { ........vector<int> nums; ........int sumOfSquares = 0; ........ ........while (sumOfSquares != 1) { ............while (n > 0) { ................int digit = n % 10; ................n /= 10; ................nums.push_back(digit); ............} ............sumOfSquares = 0; ............for (int i : nums) ................sumOfSquares += pow(i, 2); ............if (sumOfSquares == 1) ................return true; ............ ............nums.clear(); ............n = sumOfSquares; ............ ............hashset[sumOfSquares]++; ............ ............if (hashset[sumOfSquares] > 1) ................return false; ........} ........ ........return false; ....} }; Time complexity : O(243 * 3 + log n + log log n + log log log n)... = O(log n). Finding the next value for a given number has a cost of O(log n) because we are processing each digit in the number, and the number of digits in a number is given by log n. Space complexity : O(log n). Closely related to the time complexity, and is a measure of what numbers we're putting in the HashSet, and how big they are. For a large enough nn, the most space will be taken by nn itself.

Intersection of Two Linked Lists Given the heads of two singly linked-lists headA and headB, return the node at which the two lists intersect. If the two linked lists have no intersection at all, return null. For example, the following two linked lists begin to intersect at node c1: The test cases are generated such that there are no cycles anywhere in the entire linked structure. Note that the linked lists must retain their original structure after the function returns. Custom Judge: The inputs to the judge are given as follows (your program is not given these inputs): intersectVal - The value of the node where the intersection occurs. This is 0 if there is no intersected node. listA - The first linked list. listB - The second linked list. skipA - The number of nodes to skip ahead in listA (starting from the head) to get to the intersected node. skipB - The number of nodes to skip ahead in listB (starting from the head) to get to the intersected node. The judge will then create the linked structure based on these inputs and pass the two heads, headA and headB to your program. If you correctly return the intersected node, then your solution will be accepted.

Hash Set Create hash set of 1 list. Iterate through the second list and, if the current node is in the hashset, then return that node. class Solution { public: ....ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) { ........ListNode *currA = headA, *currB = headB; ........unordered_set<ListNode*> usetB; ........ ........while (currB) { ............usetB.insert(currB); ............currB = currB->next; ........} ........ ........while (currA) { ............if (usetB.find(currA) != usetB.end()) ................return currA; ............currA = currA->next; ........} ........ ........return NULL; ....} }; Two Pointers Calculate the difference in length between list1 and list2. Iterate through the longer list by len(list1) - len(list2). Now, list1 and list2 are even length. Iterate through both lists and if the node pts are equal, then return that node. class Solution { public: ....ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) { ........ListNode *nodeA = headA, *nodeB = headB; ........int lenA = 0, lenB = 0, diff = 0;; ........ ........while (nodeA || nodeB) { ............if (nodeA) { ................lenA++; ................nodeA = nodeA->next; ............} ............if (nodeB) { ................lenB++; ................nodeB = nodeB->next; ............} ........} ........ ........diff = abs(lenA - lenB); ........nodeA = headA; ........nodeB = headB; ........ ........while (nodeA || nodeB) { ............if (diff) { ................if (lenA > lenB) ....................nodeA = nodeA->next; ................else if (lenB > lenA) ....................nodeB = nodeB->next; ................diff--; ............} else { ................if (nodeA == nodeB) ....................return nodeA; ................nodeA = nodeA->next; ................nodeB = nodeB->next; ............} ........} ........ ........return NULL; ....} };

Task Scheduler Given a characters array tasks, representing the tasks a CPU needs to do, where each letter represents a different task. Tasks could be done in any order. Each task is done in one unit of time. For each unit of time, the CPU could complete either one task or just be idle. However, there is a non-negative integer n that represents the cooldown period between two same tasks (the same letter in the array), that is that there must be at least n units of time between any two same tasks. Return the least number of units of times that the CPU will take to finish all the given tasks. Example 1: Input: tasks = ["A","A","A","B","B","B"], n = 2 Output: 8 Explanation: A -> B -> idle -> A -> B -> idle -> A -> B There is at least 2 units of time between any two same tasks.

Sol 1: Math ["A","A","A","B","B","B"], n = 2 1 2 3.... 4 5 6.... 7 8 A->B->idle->A->B->idle->A->B Sol 1: idle time + numTasks 1) Build frequency hashmap vector<char>(26 alphabetic letters) 2) Find the most frequent task 3) Count frequency of the most frequent task 4) Return max(number of tasks, idle_slots * idle_period + f_max_freq) class Solution { public: ....int leastInterval(vector<char>& tasks, int n) { ........// [3,3,0,...,0,0,0] ........vector<int> frequencies(26); ........for (int t : tasks) ............frequencies[t - 'A']++; ........ ........// Find frequency of most frequent task(s) ........int f_max = 0; ........for (int f : frequencies) ............f_max = max(f_max, f); ........ ........// Count number of tasks that have f_max frequency ........int f_max_freq = 0; ........for (int f : frequencies) ............if (f == f_max) ................f_max_freq++; ........ ........// Two possible situations: ........// 1) The most frequent task is NOT frequent enough ........//....to force the presence of idle slots. Result is ........//....the total number of tasks. ........//....A B C A D E A F ........//.... ^ ^ ^ ^.... <-- cooling period = 2 ........// 2) The most frequent task is frequent enough to ........//....force some idle slots. Result is: ........//....(n+1) * (f_max-1) + n_max ........//....(n+1) = idle_period = n for cooling period + 1 CPU time to run most freq task ........//....(f_max+1) = idle_slots = most freq task + cooling period ........//....n_max = freq count of most frequent task ........//....A B C A B _ A _ _ A _ _ A ........//.... ^ ^ ^ ^ ^ ^ ^ ^ <-- cooling period = 2 ........int idle_period = n + 1; ........int idle_slots = f_max - 1; ........return max((int)tasks.size(), idle_period * idle_slots + f_max_freq); ....} }; Sol 2: Greedy The total number of CPU intervals we need consists of busy and idle slots. Number of busy slots is defined by the number of tasks to execute: len(tasks). The problem is to compute a number of idle slots. Maximum possible number of idle slots is defined by the frequency of the most frequent task: idle_time <= (f_max - 1) * n. idle_time -= min(f_max - 1, frequencies[i]); You want to "sprinkle" the current task across the idle slots. f_max - 1 tells you how many idle_slots there are. In most cases, f_max - 1 > frequencies[i], except when two tasks have the same frequency. Then the last task wouldn't fill an idle_slot, it'd be appended to the task sequence e.g. for ["A", "A", "B", "B"] and n = 2, this is A B _ A B (with an empty idle slot in the middle). Time: O(n log n) Space: O(26) => O(1) class Solution { public: ....int leastInterval(vector<char>& tasks, int n) { ........// [3,3,0,...,0,0,0] ........vector<int> frequencies(26); ........for (int t : tasks) ............frequencies[t - 'A']++; ........ ........// [0,0,0,...,0,3,3] ........sort(frequencies.begin(), frequencies.end()); ........ ........// max frequency ........int f_max = frequencies[25]; ........ ........// idle time = idle_slots * idle_period ........int idle_time = (f_max - 1) * n; ........ ........ ........for (int i = frequencies.size() - 2; ............ i >= 0 && idle_time > 0; i--) { ............// f_max - 1 tells you how many idle_slots there are. ............// In most cases, f_max - 1 > frequencies[i], except ............// when two tasks have the same frequency. Then the ............// last task wouldn't fill an idle_slot, it'd be ............// appended to the task sequence e.g. for ............// ["A", "A", "B", "B"] and n = 2, this is A B _ A B ............// (with an empty idle slot in the middle). ............idle_time -= min(f_max - 1, frequencies[i]); ........} ........idle_time = max(0, idle_time); ........ ........return idle_time + tasks.size(); ....} };

Binary Tree Inorder Traversal Given the root of a binary tree, return the inorder traversal of its nodes' values. Input: root = [1,null,2,3] Output: [1,3,2]

Sol 1: Recursive Left -> Visit -> Right class Solution { public: ....void inorderTraversalHelper(TreeNode* root, vector<int> *result) { ........if (!root) ............return; ........ ........inorderTraversalHelper(root->left, result);........ ........result->push_back(root->val);........ ........inorderTraversalHelper(root->right, result); ....} .... ....vector<int> inorderTraversal(TreeNode* root) { ........vector<int> result; ........inorderTraversalHelper(root, &result); ........return result; ....} }; Sol 2: Iterative class Solution { public: ....vector<int> inorderTraversal(TreeNode* root) { ........vector<int> res; ........ ........if (!root) ............return res; ........ ........stack<TreeNode*> st; ........TreeNode* curr = root; ........ ........// We don't initially add curr to the stack since the inner ........// while loop handles adding nodes to the stack ........while (curr || !st.empty()) { ............// Add all left nodes to the stack first ............while (curr) { ................st.push(curr); ................curr = curr->left; ............} ............ ............// Get current value from stack ............curr = st.top(); ............st.pop(); ............ ............// Add current value to result ............res.emplace_back(curr->val); ............ ............// Add right node to stack ............curr = curr->right; ........} ........ ........return res; ....} };

54. Spiral Matrix Given an m x n matrix, return all elements of the matrix in spiral order. Example 1: Input: matrix = [[1,2,3],[4,5,6],[7,8,9]] Output: [1,2,3,6,9,8,7,4,5] Example 2: Input: matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]] Output: [1,2,3,4,8,12,11,10,9,5,6,7]

Sol 1: Shrink boundaries after traversing each direction 1) Init result. Init directional bounaries: up=0, right=matrix.size-1, down=matrix[0].size-1, left=0 2) While result.size < rows * cols, traverse left-right, up-down, right-left, down-up directions. 3) Shrink boundary for up, down, left, right. 4) Return result Time: O(N), Space: O(1) class Solution { public: ....vector<int> spiralOrder(vector<vector<int>>& matrix) { ........vector<int> res; ........int rows = matrix.size(); ........int cols = matrix[0].size(); ........int up = 0; ........int right = cols - 1; ........int down = rows - 1; ........int left = 0; ........ ........while (res.size() < rows * cols) { ............// Traverse from left to right ............for (int col = left; col <= right; col++) ................res.emplace_back(matrix[up][col]); ............ ............// Traverse from up to down ............for (int row = up + 1; row <= down; row++) ................res.emplace_back(matrix[row][right]); ............ ............// If up and down are not the same row ............if (up != down) ................// Traverse from right to left ................for (int col = right - 1; col >= left; col--) ....................res.emplace_back(matrix[down][col]); ............// If left and right aren't the same column ............if (left != right) ................// Traverse from bottom to up ................for (int row = down - 1; row > up; row--) ....................res.emplace_back(matrix[row][left]); ............ ............// Shrink matrix boundaries ............up++; ............right--; ............down--; ............left++; ........} ........ ........return res; ....} };

Kth Largest Element in an Array Given an integer array nums and an integer k, return the kth largest element in the array. Note that it is the kth largest element in the sorted order, not the kth distinct element. Input: nums = [3,2,1,5,6,4], k = 2 Output: 5

Sort Sort nums. Return the k'th largest element. class Solution { public: ....int findKthLargest(vector<int>& nums, int k) { ........if (!nums.size()) ............return 0; ........sort(nums.begin(), nums.end()); ........return nums[nums.size() - k]; ....} };

Merge Intervals Given an array of intervals where intervals[i] = [starti, endi], merge all overlapping intervals, and return an array of the non-overlapping intervals that cover all the intervals in the input. Example 1: Input: intervals = [[1,3],[2,6],[8,10],[15,18]] Output: [[1,6],[8,10],[15,18]] Explanation: Since intervals [1,3] and [2,6] overlaps, merge them into [1,6].

Sort and Merge Sort intervals array by the starting number in each interval. That way, you only have to worry about the end value for each interval. Then, iterate through Intervals and, if the current interval end >= the i'th interval start (intervals[i][0]), then set current interval to max(curr_end, next_end); else, append interval to the result and update current interval. class Solution { public: ....vector<vector<int>> merge(vector<vector<int>>& intervals) { ........vector<vector<int>> result; ........ ........if (!intervals.size()) ............return result; ........ ........sort(intervals.begin(), intervals.end(), ............[] (vector<int>& a, vector<int>& b) { ................return a[0] < b[0]; ............}); ........ ........vector<int> curr_int = intervals[0]; ........ ........for (int i = 0; i < intervals.size(); i++) { ............int curr_start = curr_int[0]; ............int curr_end = curr_int[1]; ............int next_start = intervals[i][0]; ............int next_end = intervals[i][1]; ............ ............if (curr_end >= next_start) { ................curr_int[1] = max(curr_end, next_end); ............} else { ................result.push_back(curr_int); ................curr_int = intervals[i]; ............} ........} ........result.push_back(curr_int); ........ ........return result; ....} };

Inorder Successor in BST Given the root of a binary search tree and a node p in it, return the in-order successor of that node in the BST. If the given node has no in-order successor in the tree, return null. The successor of a node p is the node with the smallest key greater than p.val. Input: root = [2,1,3], p = 1 Output: 2 Explanation: 1's in-order successor node is 2. Note that both p and the return value is of TreeNode type.

Successor Node/Using BST Properties As you traverse tree, go right if p->val >= root, else go left if p->val < root. If going left, set successor. O(h) class Solution { public: ....TreeNode* inorderSuccessor(TreeNode* root, TreeNode* p) { ........TreeNode* successor = NULL; ........ ........while (root) { ............if (p->val >= root->val) { ................root = root->right; ............} else { ................successor = root; ................root = root->left; ............} ........} ........ ........return successor; ....} }; Check Inorder Previous Node Return current node whose previous node equals p->val. O(n). class Solution { public: ....TreeNode* inorderSuccessor(TreeNode* root, TreeNode* p) { ........if (!root || !p) ............return NULL; ........ ........stack<TreeNode*> st; ........TreeNode* itr = root, *prev = NULL; ........ ........while (itr || !st.empty()) { ............while (itr) { ................st.push(itr); ................itr = itr->left; ............} ............ ............itr = st.top(); ............st.pop(); ............ ............if (prev && prev->val == p->val) ................return itr; ............ ............prev = itr; ............itr = itr->right; ........} ........ ........return NULL; ....} };

3Sum Given an integer array nums, return all the triplets [nums[i], nums[j], nums[k]] such that i != j, i != k, and j != k, and nums[i] + nums[j] + nums[k] == 0. Notice that the solution set must not contain duplicate triplets. Input: nums = [-1,0,1,2,-1,-4] Output: [[-1,-1,2],[-1,0,1]]

Two Pointers Sort nums array. Loop through each element in nums, eliminate duplicate permutations using "if (i > 0 && nums[i] == nums[i-1]) {continue;}". Else, iterate through the rest of the elements with a Left and Right pointer. Left iterates rightward and Right iterates leftward. Calculate sum = nums[i] + nums[left] + nums[right]. If sum > 0, then right--; If sum < 0, then left++; else push the result to the output vector and keep iterating left++ until nums[left] != nums[left-1] and left < right. class Solution { public: ....vector<vector<int>> threeSum(vector<int>& nums) { ........vector<vector<int>> result; ........sort(nums.begin(), nums.end()); ........ ........for (int i = 0; i < nums.size(); i++) { ............if (i > 0 && nums[i] == nums[i-1]) ................continue; ............ ............for (int l = i+1, r = nums.size()-1; l < r;) { ................int sum = nums[i] + nums[l] + nums[r]; ................if (sum < 0) ....................l++; ................else if (sum > 0) ....................r--; ................else { ....................result.push_back(vector<int>{ nums[i], nums[l], nums[r] }); ....................l++; ....................while (l < r && nums[l] == nums[l-1]) ........................l++; ................} ............} ........} ........ ........return result; ....} }; Hash Set Sort nums array. Create hash map of nums array. Instead of eliminating duplicates using "if (i > 0 && nums[i] == nums[i-1]", check if nums[i] is in the dups hash set. If not, then add nums[i] to the hash set and proceed with the inner for loop, like in the 2 ptr technique. Instead of keep iterating left++ until nums[left] != nums[left-1], just add to the result vector if the hash map's index of the complement > left? class Solution { public: ....vector<vector<int>> threeSum(vector<int>& nums) { ........vector<vector<int>> result; ........unordered_map<int, int> map; ........ ........sort(nums.begin(), nums.end()); ........for (int i = 0; i < nums.size(); i++) ............map[nums[i]] = i; ................ ........for (int i = 0; i < nums.size(); i++) { ............if (i > 0 && nums[i] == nums[i-1]) ................continue; ............ ............for (int l = i+1; l < nums.size();) { ................int comp = -nums[i] - nums[l]; ................auto it = map.find(comp); ................if (it != map.end() && it->second != i && it->second != l && it->second > l) ....................result.push_back(vector<int>{ nums[i], nums[l], comp }); ................l++; ................while (l < nums.size() && nums[l] == nums[l-1]) ....................l++; ............} ........} ........ ........return result; ....} };

Populating Next Right Pointers in Each Node You are given a perfect binary tree where all leaves are on the same level, and every parent has two children. The binary tree has the following definition: struct Node { int val; Node *left; Node *right; Node *next; } Populate each next pointer to point to its next right node. If there is no next right node, the next pointer should be set to NULL. Initially, all next pointers are set to NULL. Input: root = [1,2,3,4,5,6,7] Output: [1,#,2,3,#,4,5,6,7,#] Explanation: Given the above perfect binary tree (Figure A), your function should populate each next pointer to point to its next right node, just like in Figure B. The serialized output is in level order as connected by the next pointers, with '#' signifying the end of each level.

Using previously established next pointers Traverse each leftmost node. For each leftmost node, set the next lower level's next pointers: (1) itr->left->next = itr->right, and (2) itr->right->next = itr->next->left only if itr->next != NULL (i.e. if this is not the last node in this level). class Solution { public: ....Node* connect(Node* root) { ........if (!root) ............return NULL; ........ ........Node* leftNode = root; ........ ........while (leftNode && leftNode->left) { ............Node* itr = leftNode; ............ ............while (itr) { ................itr->left->next = itr->right; ................ ................if (itr->next) ....................itr->right->next = itr->next->left; ................ ................itr = itr->next; ............} ............ ............leftNode = leftNode->left; ........} ........ ........return root; ....} };

45. Jump Game II Given an array of non-negative integers nums, you are initially positioned at the first index of the array. Each element in the array represents your maximum jump length at that position. Your goal is to reach the last index in the minimum number of jumps. You can assume that you can always reach the last index. Example 1: Input: nums = [2,3,1,1,4] Output: 2 Explanation: The minimum number of jumps to reach the last index is 2. Jump 1 step from index 0 to 1, then 3 steps to the last index. Example 2: Input: nums = [2,3,0,1,4] Output: 2

l r 0 1 2 3 4 2,3,1,1,4 0|1 1|2 2 <-- BFS level = steps to reach that cell l=r+1 r = nums[i]+i = 3+1 = 4 Approach 1: BFS/Greedy Time: O(N), Space: O(1) 1) Init left=0, right=0, farthestJump, and result=0; 2) While right has not reached destination cell, find the farthest cell that we can jump as "i+nums[i]" among all cells in current BFS level, which ranges from left index to right index. Then, update left=right+1 and right=farthestJump, and increment result. 3) Return result (jump count) Note: DP approach is O(N^2) time/O(1) space. Greedy/BFS approach is O(N) time/O(N) space. class Solution { public: ....// Greedy Approach ....int jump(vector<int>& nums) { ........int res = 0; ........int left = 0, right = 0, farthestJump; ........ ........// Stop looping once you reach the destination ........while (right < nums.size() - 1) { ............farthestJump = 0; ............ ............// Get the farthest index that we can jump to ............// within the current BFS level ............for (int i = left; i <= right; i++) ................farthestJump = max(farthestJump, i + nums[i]); ............ ............// Update window indexes ............left = right + 1; ............right = farthestJump; ............ ............// Update number of jumps result ............res++; ........} ........ ........return res; ....} };


Related study sets

Parallel, Perpendicular,Slope, Slope-Intercept Form, Standard Form, and Point-Slope Form, Chapter 6 Parallel and Perpendicular Lines

View Set