785. Is Graph Bipartite? There is an undirected graph with n nodes, where each node is numbered between 0 and n - 1. You are given a 2D array graph, where graph[u] is an array of nodes that node u is adjacent to. More formally, for each v in graph[u], there is an undirected edge between node u and node v. The graph has the following properties: There are no self-edges (graph[u] does not contain u). There are no parallel edges (graph[u] does not contain duplicate values). If v is in graph[u], then u is in graph[v] (the graph is undirected). The graph may not be connected, meaning there may be two nodes u and v such that there is no path between them. A graph is bipartite if the nodes can be partitioned into two independent sets A and B such that every edge in the graph connects a node in set A and a node in set B. Return true if and only if it is bipartite. Example 1: Input: graph = [[1,2,3],[0,2],[0,1,3],[0,2]] Output: false Explanation: There is no way to partition the nodes into two independent sets such that every edge connects a node in one and a node in the other. Example 2: Input: graph = [[1,3],[0,2],[1,3],[0,2]] Output: true Explanation: We can partition the nodes into two sets: {0, 2} and {1, 3}.
Approach #1: Coloring by BFS For each node in the graph, color current node red and neighboring nodes as blue. If neighbor's color == current node's color, return false. Time: O(N + E), N = nodes in graph, E = edges in graph Space: O(N), colors vector is size N class Solution { public: ....bool isBipartite(vector<vector<int>>& graph) { ........// 1 = red, 0 = not colored, -1 = blue ........vector<int> colors(graph.size(), 0); ........queue<int> q; ........ ........// For each node in the graph, color current ........// node red and neighboring nodes as blue ........for (int i = 0; i < graph.size(); i++) { ............// If node already has a color, skip ............if (colors[i]) ................continue; ............ ............// Color current node as red ............colors[i] = 1; ............ ............// BFS using queue ............q.push(i); ............ ............while (!q.empty()) { ................int temp = q.front(); ................ ................for (auto neighbor : graph[temp]) { // If neighbor does not have a color yet ....................if (!colors[neighbor]){ ........................// Color neighbor with opposite color ........................colors[neighbor] = -colors[temp]; ........................q.push(neighbor); ....................} else if (colors[neighbor] == colors[temp]) { ........................// If the neighbor has the same color - can't bipartite. ........................return false; ....................} ................} ................q.pop(); ............} ........} ........return true; ....} };
317. Shortest Distance from All Buildings You are given an m x n grid grid of values 0, 1, or 2, where: each 0 marks an empty land that you can pass by freely, each 1 marks a building that you cannot pass through, and each 2 marks an obstacle that you cannot pass through. You want to build a house on an empty land that reaches all buildings in the shortest total travel distance. You can only move up, down, left, and right. Return the shortest travel distance for such a house. If it is not possible to build such a house according to the above rules, return -1. The total travel distance is the sum of the distances between the houses of the friends and the meeting point. The distance is calculated using Manhattan Distance, where distance(p1, p2) = |p2.x - p1.x| + |p2.y - p1.y|. Example 1: Input: grid = [[1,0,2,0,1],[0,0,0,0,0],[0,0,1,0,0]] Output: 7 Explanation: Given three buildings at (0,0), (0,4), (2,2), and an obstacle at (0,2). The point (1,2) is an ideal empty land to build a house, as the total travel distance of 3+3+1=7 is minimal. So return 7. Example 2: Input: grid = [[1,0]] Output: 1 Example 3: Input: grid = [[1]] Output: -1
Approach 1: BFS from Empty Land to House (5%) class Solution { public: ....int bfs(vector<vector<int>>& grid, int row, int col, int totalHouses) { ........int rows = grid.size(); ........int cols = grid[0].size(); ........int dirs[4][2] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}}; ........int distance = 0; ........ ........vector<vector<bool>> visited(rows, vector<bool>(cols, false)); ........ ........queue<pair<int, int>> q; ........q.push({ row, col }); ........visited[row][col] = true; ........ ........int steps = 0; ........while (!q.empty() && totalHouses) { ............for (int i = q.size(); i > 0; i--) { ................pair<int, int> curr = q.front(); ................q.pop(); ................ ................row = curr.first; ................col = curr.second; ................ ................if (grid[row][col] == 1) { ....................distance += steps; ....................totalHouses--; ....................continue; ................} ................ ................for (auto &dir : dirs) { ....................int r = row + dir[0]; ....................int c = col + dir[1]; .................... ....................if (r >= 0 && r < rows && ........................c >= 0 && c < cols && ........................grid[r][c] != 2 && ........................!visited[r][c]) { ........................visited[r][c] = true; ........................q.push({ r, c }); ....................} ................} ............} ............ ............steps++; ........} ........ ........if (totalHouses) { ............for (int r = 0; r < rows; r++) { ................for (int c = 0; c < cols; c++) { ....................if (grid[r][c] == 0 && visited[r][c]) ........................grid[r][c] = 2; ................} ............} ............ ............return INT_MAX; ........} ........ ........return distance; ....} .... ....int shortestDistance(vector<vector<int>>& grid) { ........int minDist = INT_MAX; ........int rows = grid.size(); ........int cols = grid[0].size(); ........int totalHouses = 0; ........ ........for (int r = 0; r < rows; r++) { ............for (int c = 0; c < cols; c++) { ................if (grid[r][c] == 1) ....................totalHouses++; ............} ........} ........ ........for (int r = 0; r < rows; r++) { ............for (int c = 0; c < cols; c++) { ................if (grid[r][c] == 0) ....................minDist = min(minDist, bfs(grid, r, c, totalHouses)); ............} ........} ........ ........return minDist == INT_MAX ? -1 : minDist; ....} }; Approach 2: BFS from House to Empty Land (45%) class Solution { public: ....void bfs(vector<vector<int>>& grid, vector<vector<vector<int>>>& distances, ............ int row, int col) { ........int rows = grid.size(); ........int cols = grid[0].size(); ........int dirs[4][2] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}}; ........ ........vector<vector<bool>> visited(rows, vector<bool>(cols, false)); ........ ........// Run iterative BFS using queue ........queue<pair<int, int>> q; ........q.push({ row, col }); ........visited[row][col] = true; ........ ........int steps = 0; ........while (!q.empty()) { ............for (int i = q.size(); i > 0; i--) { ................pair<int, int> curr = q.front(); ................q.pop(); ................ ................row = curr.first; ................col = curr.second; ................ ................// If this is an empty land ................if (grid[row][col] == 0) { ....................// Add the steps from a house to this empty land ....................distances[row][col][0] += steps; .................... ....................// Increment total houses that can reach this empty land ....................distances[row][col][1]++; ................} ................ ................// Add the next valid step location to the queue ................for (auto &dir : dirs) { ....................int r = row + dir[0]; ....................int c = col + dir[1]; .................... ....................if (r >= 0 && r < rows && ........................c >= 0 && c < cols && ........................grid[r][c] == 0 && ........................!visited[r][c]) { ........................visited[r][c] = true; ........................q.push({ r, c }); ....................} ................} ............} ............ ............// Increment steps for this current level in BFS ............steps++; ........} ....} .... ....int shortestDistance(vector<vector<int>>& grid) { ........int minDist = INT_MAX; ........int rows = grid.size(); ........int cols = grid[0].size(); ........int totalHouses = 0; ........ ........// Stores <cumulative distance from all 1's to 0's, house count> ........vector<vector<vector<int>>> distances(rows, vector<vector<int>>(cols, vector<int>(2))); ........ ........for (int r = 0; r < rows; r++) { ............for (int c = 0; c < cols; c++) { ................if (grid[r][c] == 1) { ....................totalHouses++; ....................bfs(grid, distances, r, c); ................} ............} ........} ........ ........for (int r = 0; r < rows; r++) { ............for (int c = 0; c < cols; c++) { ................if (distances[r][c][1] == totalHouses) { ....................minDist = min(minDist, distances[r][c][0]); ................} ............} ........} ........ ........return minDist == INT_MAX ? -1 : minDist; ....} }; Approach 3: BFS from House to Empty Land + Grid for Visited array (100%) class Solution { public: ....int shortestDistance(vector<vector<int>>& grid) { ........int minDist = INT_MAX; ........int rows = grid.size(); ........int cols = grid[0].size(); ........int dirs[4][2] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}}; ........int emptyLandValue = 0; ........vector<vector<int>> distances(rows, vector<int>(cols, 0)); ........ ........for (int r = 0; r < rows; r++) { ............for (int c = 0; c < cols; c++) { ................// If this is a house ................if (grid[r][c] == 1) { ....................// Reset minDist to INT_MAX. Since we add ....................// distance from house to empty land, only ....................// the last house's run of BFS will count ....................// for minDist. ....................minDist = INT_MAX; .................... ....................// Iterate BFS using queue, starting from row/col ....................queue<pair<int, int>> q; ....................q.push({ r, c }); .................... ....................int steps = 0; ....................while (!q.empty()) { ........................// Record steps from current house ........................steps++; ........................ ........................// Iterate through each node in the queue. ........................// Traverse backwards through q since q will ........................// grow as we push new nodes. ........................for (int level = q.size(); level > 0; level--) { ............................// Get next node/land ............................pair<int, int> curr = q.front(); ............................q.pop(); ............................ ............................for (auto &dir : dirs) { ................................// Get next direction ................................int newRow = curr.first + dir[0]; ................................int newCol = curr.second + dir[1]; ................................// If the next row/col is in the grid's ................................// bounds AND this is an empty land ................................if (newRow >= 0 && newRow < rows && ....................................newCol >= 0 && newCol < cols && ....................................grid[newRow][newCol] == emptyLandValue) { ....................................// Decrement this location's empty ....................................// land value to mark it as visited ....................................grid[newRow][newCol]--; .................................... ....................................// Push next location to the queue ....................................q.push({ newRow, newCol }); ....................................// Update distance from current house ....................................// to empty land ....................................distances[newRow][newCol] += steps; .................................... ....................................// Update minimum distance ....................................minDist = min(minDist, distances[newRow][newCol]); ................................} ............................} ........................} ....................} ....................// Decrement the empty land value. ....................emptyLandValue--; ................} ............} ........} ........ ........ ........return minDist == INT_MAX ? -1 : minDist; ....} };
Palindrome Permutation Given a string s, return true if a permutation of the string could form a palindrome. Example 1: Input: s = "code" Output: false Example 2: Input: s = "aab" Output: true Example 3: Input: s = "carerac" Output: true
Approach 1: Bit Manipulation Why "(lettersUsed & (lettersUsed - 1)) == 0;"? If there is a palindrome, then bitmap will either equal 0x0 or have 1 bit set. We do "(bitmap - 1)" so that we flip all the bits less significant than the set 1 bit. By flipping all the bits less significant than the 1 bit, then "bitmap & (bitmap - 1)" will have all the bits cancel out to 0x0. For example, if 1 bit is set in the palindrome "aao", we have - bitmap : 01000000 00000000 bitmap - 1: 00111111 11111111 bitmap & (bitmap - 1): 00000000 00000000 Since all bits cancel out to 0x0 (bitmap & (bitmap - 1) == 0), we have a palindrome. Alternatively, if no bits are set in bitmap, then "bitmap - 1" will invert all the bits in bitmap. Then, "bitmap & (bitmap - 1)" will result in "0x0 & 0xffffffff = 0", which results in a valid palindrome. If this is an invalid palindrome, then there is more than 1 bit set in bitmap, resulting in "bitmap & (bitmap - 1)" > 0. class Solution { public: ....bool canPermutePalindrome(string s) {........ ........// Int has 32 bits, which is enough to store ........// 26 letters in the alphabet ........// e.g. a=0, b=1, ..., z=25 ........int lettersUsed = 0; ........ ........// x ^ 0 = x ........// x ^ x = 0 ........// First time letter is seen, set bit in lettersUsed ........// Second time letter is seen, unset bit in lettersUsed ........for (char c : s) ............lettersUsed ^= 1 << (c - 'a'); ........ ........// If there is at most single 1 bit remaining, ........// then it is a palindrome. You can quickly test this ........// by checking if the least significant 1 bit (n & -n) ........// is the same as itself. ........return (lettersUsed & (lettersUsed - 1)) == 0; ....} }; Approach 2: Hash Set class Solution { public: ....bool canPermutePalindrome(string s) { ........unordered_map<char, int> um; ........int count = 0; ........ ........for (char c : s) ............um[c] = !um[c]; ........ ........for (auto i : um) { ............if (i.second == 1) ................count++; ........} ........ ........return count <= 1; ....} };
338. Counting Bits Given an integer n, return an array ans of length n + 1 such that for each i (0 <= i <= n), ans[i] is the number of 1's in the binary representation of i. Example 1: Input: n = 2 Output: [0,1,1] Explanation: 0 --> 0 1 --> 1 2 --> 10 Example 2: Input: n = 5 Output: [0,1,1,2,1,2] Explanation: 0 --> 0 1 --> 1 2 --> 10 3 --> 11 4 --> 100 5 --> 101
Approach 1: Bit Manipulation class Solution { public: ....vector<int> countBits(int n) { ........vector<int> result(n + 1); ........ ........// Iterate through each input value ........for (int i = 1; i <= n; i++) { ............int count = 0; ............int num = i; ............ ............// Count the number of set bits ............// "num & num - 1" gets the least ............// significant set bit in O(1) time ............while (num) { ................count++; ................num &= num - 1; ............} ............ ............result[i] = count; ........} ........ ........return result; ....} }; Approach 4: DP + Last Set Bit Let look at the relation between x and x' = x/2 We can see that x' is differ than x by one bit, because x' can be considered as the result of removing the least significant bit of x (i.e. x >> 1) Thus, we have the following transition function of pop count P(x): P(x) = P(x / 2) + (x % 2) With the same logic as previous approaches, we can also manipulate the last set bit. Last set bit is the rightmost set bit. Setting that bit to zero with the bit trick, x &= x - 1, leads to the following transition function: P(x) = P(x & (x - 1)) + 1 1 + result[n - offset] i bits result[i] 0 0 0 (base case) 1 0001 1 (result[0]=0 + 1 = 1) 2 0010 1 (result[0]=0 + 1 = 1) 3 0011 2 (result[2]=1 + 1 = 2) 4 0100 1 (result[0]=0 + 1 = 1) 5 0101 2 (result[4]=1 + 1 = 2) 6 0110 2 (result[4]=1 + 1 = 2) 7 0111 3 (result[6]=2 + 1 = 3) 8 1000 1 (result[0]=0 + 1 = 1) 9 1001 2 (result[8]=1 + 1 = 2) 10 1010 2 (result[8]=1 + 1 = 2) class Solution { public: ....vector<int> countBits(int n) { ........vector<int> result(n + 1); ........ ........// Iterate through each input value ........for (int i = 1; i <= n; i++) { ............// Count the number of set bits ............result[i] = result[i & (i - 1)] + 1; ........} ........ ........return result; ....} };
Add Binary Given two binary strings a and b, return their sum as a binary string. Example 1: Input: a = "11", b = "1" Output: "100" Example 2: Input: a = "1010", b = "1011" Output: "10101"
Approach 1: Bit-by-Bit Computation Traversing string a and b from right to left, calculate carry=(sum of set bits). If carry=[0,2], then append 0 to result. If carry=[1,3], then append 1 to result. Then, update carry/2. That's a good old classical algorithm, and there is no conversion from binary string to decimal and back here. Let's consider the numbers bit by bit starting from the lowest one and compute the carry this bit will add. Start from carry = 0. If number a has 1-bit in this lowest bit, add 1 to the carry. The same for number b: if number b has 1-bit in the lowest bit, add 1 to the carry. At this point the carry for the lowest bit could be equal to (00)_2(00)2, (01)_2(01)2, or (10)_2(10)2. Now append the lowest bit of the carry to the answer, and move the highest bit of the carry to the next order bit. Repeat the same steps again, and again, till all bits in a and b are used up. If there is still nonzero carry to add, add it. Now reverse the answer string and the job is done. class Solution { public: ..../* .... a = 1010 = 10 .... b = 1011 = 11 ....sum = 10101 = 21 ....----- i=3, j=3, carry=0 ----- ....carry = (carry=0) + (a[3]=0) + (b[3]=1) = 1 ....sum = (carry=1)%2 + (sum="") = "1" + "" = "1" ....(carry=1)/2 = 0 ....----- i=2, j=2, carry=0 ----- ....carry = (carry=0) + (a[2]=1) + (b[2]=1) = 2 ....sum = (carry=2)%2 + (sum="1") = "0" + "1" = "01" ....(carry=2/2) = 1 ....----- i=1, j=1, carry=1 ----- ....carry = (carry=1) + (a[1]=0) + (b[1]=0) = 1 ....sum = (carry=1)%2 + (sum="01") = "1" + "01" = "101" ....(carry=1)/2 = 0 ....----- i=0, j=0, carry=0 ----- ....carry = (carry=0) + (a[0]=1) + (b[0]=1) = 2 ....sum = (carry=2)%2 + (sum="101") = "0" + "101" = "0101" ....(carry=2)/2 = 1 ....----- i=0, j=0, carry=1 ----- ....carry = skip since i<0 and j<0 ....sum = (carry=1)%2 + (sum="0101") = "1" + "0101" = "10101" ....(carry=1)/2 = 0 ....*/ ....string addBinary(string a, string b) { ........int i = a.length() - 1; ........int j = b.length() - 1; ........int carry = 0; ........string sum = ""; ........ ........while (i >= 0 || j >= 0 || carry) { ............// Calculate sum of set bits at a[i] and b[j] ............if (i >= 0) ................carry += a[i--] - '0'; ............if (j >= 0) ................carry += b[j--] - '0'; ............ ............// Insert bit at the front of the string ............// If carry == 0 or 2, then insert 0. ............// If carry == 1 or 3, then insert 1. ............sum = (char)(carry % 2 + '0') + sum; ............ ............// If carry == 2 or 3, then carry=1. ............// If carry < 2, then no carry ............carry /= 2; ........} ........return sum; ....} };
1428. Leftmost Column with at Least a One A row-sorted binary matrix means that all elements are 0 or 1 and each row of the matrix is sorted in non-decreasing order. Given a row-sorted binary matrix binaryMatrix, return the index (0-indexed) of the leftmost column with a 1 in it. If such an index does not exist, return -1. You can't access the Binary Matrix directly. You may only access the matrix using a BinaryMatrix interface: BinaryMatrix.get(row, col) returns the element of the matrix at index (row, col) (0-indexed). BinaryMatrix.dimensions() returns the dimensions of the matrix as a list of 2 elements [rows, cols], which means the matrix is rows x cols. Submissions making more than 1000 calls to BinaryMatrix.get will be judged Wrong Answer. Also, any solutions that attempt to circumvent the judge will result in disqualification. For custom testing purposes, the input will be the entire binary matrix mat. You will not have access to the binary matrix directly. Example 1: Input: mat = [[0,0],[1,1]] Output: 0 Example 2: Input: mat = [[0,0],[0,1]] Output: 1 Example 3: Input: mat = [[0,0],[0,0]] Output: -1 Example 4: Input: mat = [[0,0,0,1],[0,0,1,1],[0,1,1,1]] Output: 1
Approach 1: Brute Force Traverse top-bottom and left-right to search for the first 1. This will timeout and be the wrong answer since it isn't optimal. Approach 2: Traverse Top-Right to Bottom-Left (OPTIMAL SLN) Traverse top-right to bottom-left to search for the bottom-leftmost 1. Time complexity : O(N + M) At each step, we're moving 1 step left or 1 step down. Therefore, we'll always finish looking at either one of the M rows or N columns. Therefore, we'll stay in the grid for at most N + M steps, and therefore get a time complexity of O(N + M). Space complexity : O(1) class Solution { public: ....int leftMostColumnWithOne(BinaryMatrix &binaryMatrix) { ........vector<int> dim = binaryMatrix.dimensions(); ........int rows = dim[0]; ........int cols = dim[1]; ........int r = 0; ........int c = cols - 1; ........ ........// Traverse the matrix from top-right to bottom-left. ........// Each row is sorted with 0's on left and 1's on right. ........// Therefore, traverse each row right-left until ........// matrix[r][c] == 0 and matrix[r][c+1] == 1. ........// Then, traverse each col from top-bottom until ........// matrix[r][c] == 0 and matrix[r+1][c] == 1. ........while (r < rows && c >= 0) { ............if (binaryMatrix.get(r, c) == 0) ................r++; ............else ................c--; ........} ........ ........// If c == cols-1, then the row contained all 0's. ........// If the row contained all 0's, then return -1. ........return c == cols - 1 ? -1 : c + 1; ....} }; Approach 3: Binary Search class Solution { public: ....int leftMostColumnWithOne(BinaryMatrix &binaryMatrix) { ........vector<int> dims = binaryMatrix.dimensions(); ........int rows = dims[0]; ........int cols = dims[1]; ........int leftmostCol = cols; ........ ........for (int r = 0; r < rows; r++) { ............// Binary search for the first 1 in the row ............int left = 0, right = cols - 1; ............while (left < right) { ................int mid = left + (right - left)/2; ................if (binaryMatrix.get(r, mid) == 0) ....................left = mid + 1; ................else ....................right = mid; ............} ............ ............// If the last element in the search space is 1, ............// then this row contained a 1. Therefore, ............// save the leftmost col in leftmostCol. ............if (binaryMatrix.get(r, left) == 1) ................leftmostCol = min(leftmostCol, left); ........} ........ ........// If leftmostCol == cols, then there weren't any ........// 1's in the matrix. ........return leftmostCol == cols ? -1 : leftmostCol; ....} };
1570. Dot Product of Two Sparse Vectors Given two sparse vectors, compute their dot product. Implement class SparseVector: SparseVector(nums) Initializes the object with the vector nums dotProduct(vec) Compute the dot product between the instance of SparseVector and vec A sparse vector is a vector that has mostly zero values, you should store the sparse vector efficiently and compute the dot product between two SparseVector. Follow up: What if only one of the vectors is sparse? Example 1: Input: nums1 = [1,0,0,2,3], nums2 = [0,3,0,4,0] Output: 8 Explanation: v1 = SparseVector(nums1) , v2 = SparseVector(nums2) v1.dotProduct(v2) = 1*0 + 0*3 + 0*0 + 2*4 + 3*0 = 8 Example 2: Input: nums1 = [0,1,0,0,0], nums2 = [0,0,0,0,2] Output: 0 Explanation: v1 = SparseVector(nums1) , v2 = SparseVector(nums2) v1.dotProduct(v2) = 0*0 + 1*0 + 0*0 + 0*0 + 0*2 = 0 Example 3: Input: nums1 = [0,1,0,0,2,0,0], nums2 = [1,0,0,0,3,0,4] Output: 6
Approach 1: Compute Each Element class SparseVector { private: ....vector<int> nums; .... public: ....SparseVector(vector<int> &nums) : nums(nums) {} .... ....// Return the dotProduct of two sparse vectors ....int dotProduct(SparseVector& vec) { ........int result = 0; ........for (int i = 0; i < nums.size(); i++) { ............result += nums[i] * vec.nums[i]; ........} ........return result; ....} }; Approach 2: Hash Map class SparseVector { ....// Stores <index, value> ....unordered_map<int, int> m; public:.... ....SparseVector(vector<int> &nums) { ........// Store the non-zero values and their ........// corresponding indices in a dictionary, ........// with the index being the key. Any index ........// that is not present corresponds to a ........// value 0 in the input array. ........for (int i = 0; i < nums.size(); i++) { ............if (nums[i]!=0) ............ m[i]=nums[i]; ........} ....} .... ....// Return the dotProduct of two sparse vectors ....int dotProduct(SparseVector& vec) {........ ........int res = 0; ........// For each non-zero number in v1's hashmap ........for (auto & elem : m) { ............// If v2's hashmap contains the same index ............if (vec.m.find(elem.first) != vec.m.end()) { ................// Then, compute the dot product ................res += elem.second * vec.m[elem.first]; ............} ........} ........return res; ....} }; Approach 3: List Pairs n = length of the input array L and L2 = number of non-zero elements for the two vectors. Time complexity: O(n) for creating the <index, value> pair for non-zero values; O(L+L2) for calculating the dot product. Space complexity: O(L) for creating the <index, value> pairs for non-zero values. O(1) for calculating the dot product. class SparseVector { private: ....vector<pair<int, int>> vmap; .... public: .... ....SparseVector(vector<int> &nums) { ........// If number is non-zero, then add the ........// <index, value> to the list ........for (int i = 0; i < nums.size(); i++) ............if (nums[i]) ................vmap.push_back(pair<int, int>(i, nums[i])); ....} .... ....// Return the dotProduct of two sparse vectors ....int dotProduct(SparseVector& vec) { ........int result = 0; ........int i = 0, j = 0; ........ ........// While v1's index i and v2's index j has ........// not reached the end ........while (i < vmap.size() && j < vec.vmap.size()) { ............// If the array index for both v1 and v2 ............if (vmap[i].first == vec.vmap[j].first) { ................// Calculate the dot product ................result += vmap[i].second * vec.vmap[j].second; ................i++; ................j++; ............} else if (vmap[i].first < vec.vmap[j].first) { ................// If array index for v1 < map key for v2 ................i++; ............} else { // if (vmap[i].first > vec.vmap[j].first) ................// If array index for v1 > map key for v2 ................j++; ............} ........} ........ ........return result; ....} };
Diameter of Binary Tree Given the root of a binary tree, return the length of the diameter of the tree. The diameter of a binary tree is the length of the longest path between any two nodes in a tree. This path may or may not pass through the root. The length of a path between two nodes is represented by the number of edges between them. Example 1: Input: root = [1,2,3,4,5] Output: 3 Explanation: 3 is the length of the path [4,2,1,3] or [5,2,1,3]. Example 2: Input: root = [1,2] Output: 1
Approach 1: DFS Recursively return the max(left, right) + 1. Set max(maxLen, left + right). class Solution { public: ....int diameterOfBinaryTree(TreeNode* root) { ........int len = 0; ........dfs(root, len); ........return len; ....} .... ....int dfs(TreeNode* root, int &len) { ........if (!root) ............return 0; ........ ........int left = dfs(root->left, len); ........int right = dfs(root->right, len); ........ ........// Max length or current node is the sum ........// of both left and right subtrees ........len = max(len, left + right); ........ ........// Choose either the left or right path ........// to return to the parent. ........// Can't return left+right because you ........// can't traverse both left and right subtrees ........// and traverse back to the parent without ........// overlap. ........return max(left, right) + 1; ....} };
10. Regular Expression Matching Given an input string s and a pattern p, implement regular expression matching with support for '.' and '*' where: '.' Matches any single character. '*' Matches zero or more of the preceding element. The matching should cover the entire input string (not partial). Example 1: Input: s = "aa", p = "a" Output: false Explanation: "a" does not match the entire string "aa". Example 2: Input: s = "aa", p = "a*" Output: true Explanation: '*' means zero or more of the preceding element, 'a'. Therefore, by repeating 'a' once, it becomes "aa". Example 3: Input: s = "ab", p = ".*" Output: true Explanation: ".*" means "zero or more (*) of any character (.)". Example 4: Input: s = "aab", p = "c*a*b" Output: true Explanation: c can be repeated 0 times, a can be repeated 1 time. Therefore, it matches "aab". Example 5: Input: s = "mississippi", p = "mis*is*p*." Output: false
Approach 1: DP + Recursion Time: O(N) Space: O(N) class Solution { public: ....bool isMatch(string s, string p) { ........// Init memoization array that stores whether ........// the result at s[i] and p[j] is valid ........vector<vector<int>> dp(s.length() + 1, vector<int>(p.length() + 1, -1)); ........return dfs(s, p, 0, 0, dp); ....} .... ....bool dfs(string& s, string& p, int i, int j, vector<vector<int>>& dp) { ........// If the current result is cached in the ........// memo array, return the cached result ........if (dp[i][j] != -1) ............return dp[i][j]; ........ ........// If the i and j reached the end of string s and p, ........// then this is a valid result. ........// If j reached the end of pattern p BUT i is not ........// at the end of s, then this is an invalid result. ........if (j >= p.length()) ............return i >= s.length(); ........ ........// If the current string and pattern char match OR ........// the pattern char is a wildcard, then it matches ........bool match = i < s.length() && (s[i] == p[j] || p[j] == '.'); ........ ........// If next pattern char is a '*' wildcard ........if (p.length() >= 2 && p[j + 1] == '*') { ............// Choose not to use a star ............bool dontUseStar = dfs(s, p, i, j + 2, dp); ............// Choose to use a star ............bool useStar = match && dfs(s, p, i + 1, j, dp); ............// If either the result to use or not use a star is valid, ............// then the current string is valid ............dp[i][j] = dontUseStar || useStar; ............return dp[i][j]; ........} else { ............// If current string/pattern match, then ............// evaluate the next string and pattern char (i+1 and j+1) ............dp[i][j] = match && dfs(s, p, i + 1, j + 1, dp); ............return dp[i][j]; ........} ....} }; Approach 2: Recursion (not optimal) You can easily add a memoization array to use DP. Time: O(2^N) Space: O(1) class Solution { public: ....bool isMatch(string s, string p) { ........if (p.empty()) ............return s.empty(); ........ ........// If the current string/pattern chars either ........// matches or uses a wildcard ........bool match = !s.empty() && (p[0] == s[0] || p[0] == '.'); ........ ........// If pattern char is '*' ........if (p.length() >= 2 && p[1] == '*') { ............// Check whether not using the star is valid ............bool dontUseStar = isMatch(s, p.substr(2)); ............ ............// Check whether using the star is valid. Can only ............// use the star if the previous s/p chars matched. ............bool useStar = match && ................isMatch(s.substr(1), p); ............ ............return dontUseStar || useStar; ........} else { // If pattern char is NOT '*' ............// If current chars match, then increment i and j ............// by 1 and check the rest of the pattern/string. ............return match && ................isMatch(s.substr(1), p.substr(1)); ........} ....} };
273. Integer to English Words Convert a non-negative integer num to its English words representation. Example 1: Input: num = 123 Output: "One Hundred Twenty Three" Example 2: Input: num = 12345 Output: "Twelve Thousand Three Hundred Forty Five" Example 3: Input: num = 1234567 Output: "One Million Two Hundred Thirty Four Thousand Five Hundred Sixty Seven" Example 4: Input: num = 1234567891 Output: "One Billion Two Hundred Thirty Four Million Five Hundred Sixty Seven Thousand Eight Hundred Ninety One"
Approach 1: Divide and conquer One could split the initial integer 1234567890 on the groups containing not more than three digits 1.234.567.890. That results in representation 1 Billion 234 Million 567 Thousand 890 and reduces the initial problem to how to convert 3-digit integer to English word. One could split further 234 -> 2 Hundred 34 into two sub-problems : convert 1-digit integer and convert 2-digit integer. The first one is trivial. The second one could be reduced to the first one for all 2-digit integers but the ones from 10 to 19 which should be considered separately. class Solution { public: ....string intToString(int num) { ........const string lessThan20[20] = ........{ "Zero", "One", "Two", "Three", "Four", "Five", ........ "Six", "Seven", "Eight", "Nine", "Ten", ........ "Eleven", "Twelve", "Thirteen", "Fourteen", ........ "Fifteen", "Sixteen", "Seventeen", ........ "Eighteen", "Nineteen" }; ........const string lessThan100[8] = ........{ "Twenty", "Thirty", "Forty", "Fifty", ........ "Sixty", "Seventy", "Eighty", "Ninety" }; ........ ........if (num >= 1000000000) { ............// Digit appends words to the result in ............// the billion range [1000000000,999999999999]. ............// Remaining recursively calls to calculate ............// the rest of the result below billion. ............string digit = intToString(num / 1000000000); ............string remaining = intToString(num % 1000000000); ............return digit + " Billion" + remaining; ........} ........if (num >= 1000000) { ............return intToString(num / 1000000); + " Million" + ................ intToString(num % 1000000); ........} ........if (num >= 1000) { ............return intToString(num / 1000) + " Thousand" + ................ intToString(num % 1000); ........} ........if (num >= 100) { ............return intToString(num / 100) + " Hundred" + ................ intToString(num % 100); ........} ........if (num >= 20) { ............// One type of base case at the end of the ............// recursive calls is lessThan100 ............string digit = lessThan100[num / 10 - 2]; ............string remaining = intToString(num % 10); ............return " " + digit + remaining; ........} ........if (num >= 1) { ............// One type of base case at the end of the ............// recursive calls is lessThan20 ............return " " + lessThan20[num]; ........} ........return ""; ....} .... ....string numberToWords(int num) { ........if (!num) return "Zero"; ........// Parse num in groups of 3 digits above 1000 - ........// billion, million, thousand. For < 1000, parse ........// hundred, tens, and single digits. ........// Remove space from beginning of the ........// returned string. ........return intToString(num).substr(1); ....} };
415. Add Strings Given two non-negative integers, num1 and num2 represented as string, return the sum of num1 and num2 as a string. You must solve the problem without using any built-in library for handling large integers (such as BigInteger). You must also not convert the inputs to integers directly. Example 1: Input: num1 = "11", num2 = "123" Output: "134" Example 2: Input: num1 = "456", num2 = "77" Output: "533" Example 3: Input: num1 = "0", num2 = "0" Output: "0"
Approach 1: Elementary Math Time: O(N) Space: O(1) class Solution { public: ....string addStrings(string num1, string num2) { ........string result; ........int carry = 0; ........int m = num1.size(), n = num2.size(); ........int i = m - 1; ........int j = n - 1; ................ ........while (i >= 0 || j >= 0 || carry) { ............int sum = (i >= 0 && isdigit(num1[i]) ? num1[i] - '0' : 0) + .................... (j >= 0 && isdigit(num2[j]) ? num2[j] - '0' : 0) + .................... carry; ............int digit = sum % 10; ............carry = sum / 10; ............ ............result += string(1, digit + '0'); ............i--; ............j--; ........} ........ ........if (carry) ............result = "1" + result; ........ ........reverse(result.begin(), result.end()); ........ ........return result; ....} };
Multiply Strings Given two non-negative integers num1 and num2 represented as strings, return the product of num1 and num2, also represented as a string. Note: You must not use any built-in BigInteger library or convert the inputs to integer directly. Example 1: Input: num1 = "2", num2 = "3" Output: "6" Example 2: Input: num1 = "123", num2 = "456" Output: "56088"
Approach 1: Elementary Math Use elementary math to calculate product. Remember that when calculating the next line in the product, add 1 zero as the last significant number (rightmost) for each line. product = num1 * num2 + carry + previous_num_at_index_i+j+1; carry = product / 10; previous_num_at_index_i+j+1 = product % 10; Then, convert the string back to numbers by adding '0' to each number. class Solution { public: ....string multiply(string num1, string num2) { ........string prod(num1.size() + num2.size(), 0); ........ ........for (int i = num1.size() - 1; i >= 0; i--) { ............int carry = 0; ............for (int j = num2.size() - 1; j >= 0; j--) { ................if (isdigit(num1[i]) && isdigit(num2[j])) { ....................// sum = num1 * num2 + carry + prev_num_at_index_i+j+1 ....................int sum = (num1[i] - '0') * (num2[j] - '0') + ........................carry + prod[i + j + 1]; .................... ....................carry = sum / 10; .................... ....................// Current number at prod[i + j + 1] is the sum ....................// of all values at that index. ....................prod[i + j + 1] = sum % 10; ................} ............} ............// If the current line result > 1, add 1 to prod[i] ............// prod[2] += 1 ............// val: _ _ 1 3 6 8 _ ............// idx: 0 1 2 3 4 5 6 ............prod[i] += carry; ........} ........ ........// Convert string back to numbers ........int startpos = prod.find_first_not_of('\0'); ........if (startpos != string::npos) { ............for (int i = startpos; i < prod.length(); i++) ................prod[i] += '0'; ............return prod.substr(startpos); ........} ........ ........// If num1 or num2 equals 0 ........return "0"; ....} }; Approach 2: Int Vector class Solution { public: ....string multiply(string num1, string num2) { ........// handle edge-case where the product is 0 ........if (num1 == "0" || num2 == "0") return "0"; ........ ........// num1.size() + num2.size() == max no. of digits ........vector<int> num(num1.size() + num2.size(), 0); ........ ........// build the number by multiplying one digit at the time ........for (int i = num1.size() - 1; i >= 0; --i) { ............for (int j = num2.size() - 1; j >= 0; --j) { ................num[i + j + 1] += (num1[i] - '0') * (num2[j] - '0'); ................num[i + j] += num[i + j + 1] / 10; ................num[i + j + 1] %= 10; ............} ........} ........ ........// skip leading 0's ........int i = 0; ........while (i < num.size() && num[i] == 0) ++i; ........ ........// transofrm the vector to a string ........string res = ""; ........while (i < num.size()) ............res.push_back(num[i++] + '0'); ........ ........return res; ....} };
349. Intersection of Two Arrays Given two integer arrays nums1 and nums2, return an array of their intersection. Each element in the result must be unique and you may return the result in any order. Example 1: Input: nums1 = [1,2,2,1], nums2 = [2,2] Output: [2] Example 2: Input: nums1 = [4,9,5], nums2 = [9,4,9,8,4] Output: [9,4] Explanation: [4,9] is also accepted.
Approach 1: Hash Map class Solution { public: ....vector<int> intersection(vector<int>& nums1, vector<int>& nums2) { ........vector<int> result; ........ ........if (!nums1.size() || !nums2.size()) ............return result; ........ ........unordered_map<int, int> um; ........for (int i : nums1) ............um[i] = 1; ........ ........for (int i = 0; i < nums2.size(); i++) { ............if (um.count(nums2[i]) && um[nums2[i]]) { ................result.push_back(nums2[i]); ................um[nums2[i]]--; ............} ........} ........ ........return result; ....} }; Approach 2: [Facebook] Assuming sorted array, find solution that is O(n) time and O(1) complexity class Solution { public: ....vector<int> intersection(vector<int>& nums1, vector<int>& nums2) { ........vector<int> result; ........ ........if (!nums1.size() || !nums2.size()) ............return result; ........ ........// For FB, assume arrays are sorted ........sort(nums1.begin(), nums1.end()); ........sort(nums2.begin(), nums2.end()); ........ ........int i = 0, j = 0;........ ........while (i < nums1.size() && j < nums2.size()) { ............if (nums1[i] < nums2[j]) { ................i++; ............} else if (nums1[i] > nums2[j]) { ................j++; ............} else { // if (nums1[i] == nums2[j]) ................// If result is empty or the most ................// recently added result != nums1[i], ................// then add to result. ................// Since "each element in the result ................// must be unique", check that last ................// result != current num. ................if (result.size() == 0 || ....................result.back() != nums1[i]) ....................result.push_back(nums1[i]); ................i++; ................j++; ............} ........} ........ ........return result; ....} };
146. LRU Cache Design a data structure that follows the constraints of a Least Recently Used (LRU) cache. Implement the LRUCache class: LRUCache(int capacity) Initialize the LRU cache with positive size capacity. int get(int key) Return the value of the key if the key exists, otherwise return -1. void put(int key, int value) Update the value of the key if the key exists. Otherwise, add the key-value pair to the cache. If the number of keys exceeds the capacity from this operation, evict the least recently used key. The functions get and put must each run in O(1) average time complexity. Example 1: Input ["LRUCache", "put", "put", "get", "put", "get", "put", "get", "get", "get"] [[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]] Output [null, null, null, 1, null, -1, null, -1, 3, 4] Explanation LRUCache lRUCache = new LRUCache(2); lRUCache.put(1, 1); // cache is {1=1} lRUCache.put(2, 2); // cache is {1=1, 2=2} lRUCache.get(1); // return 1 lRUCache.put(3, 3); // LRU key was 2, evicts key 2, cache is {1=1, 3=3} lRUCache.get(2); // returns -1 (not found) lRUCache.put(4, 4); // LRU key was 1, evicts key 1, cache is {4=4, 3=3} lRUCache.get(1); // return -1 (not found) lRUCache.get(3); // return 3 lRUCache.get(4); // return 4
Approach 1: Hash Map + Doubly Linked List class LRUCache { private: ....// unordered_map<key, pair<value, list<int>::iterator>> ....typedef list<int> LI; ....typedef pair<int, LI::iterator> PLI; ....typedef unordered_map<int, PLI> MPLI; ....MPLI cache; ....LI lru; ....int capacity; .... ....void touch(MPLI::iterator it) { ........// Get key ........int key = it->first; ........// Erase node from wherever it is in the list ........lru.erase(it->second.second); ........// Add node back to the front of the list ........lru.push_front(key); ........// Change list<int>::iterator to point to the ........// front of the list ........it->second.second = lru.begin(); ....} .... public: ....LRUCache(int capacity) : capacity(capacity) {} .... ....int get(int key) { ........// Find the key in the hash map ........MPLI::iterator it = cache.find(key); ........// If the key is not in the hash map, return -1 ........if (it == cache.end()) ............return -1; ........// Move node to the front of the list since it ........// is the most recently used node ........touch(it); ........// Return key's value ........return it->second.first; ....} .... ....void put(int key, int value) { ........// Find the key in the hash map ........MPLI::iterator it = cache.find(key); ........if (it != cache.end()) { ............// If the node is in the list, move it to ............// the front of the list and update it's value ............touch(it); ........} else { ............// If cache size exceeds capacity, remove the ............// key-value-itr from the LRU cache and ............// pop the LRU node from the back of the list ............if (cache.size() >= capacity) { ................cache.erase(lru.back()); ................lru.pop_back(); ............} ............// Add the key to the front of the LRU list ............lru.push_front(key); ........} ........// Set the key's value and iterator in the LRU list ........cache[key] = { value, lru.begin() }; ....} }; /** * Your LRUCache object will be instantiated and called as such: * LRUCache* obj = new LRUCache(capacity); * int param_1 = obj->get(key); * obj->put(key,value); */
47. Permutations II Given a collection of numbers, nums, that might contain duplicates, return all possible unique permutations in any order. Example 1: Input: nums = [1,1,2] Output: [[1,1,2], [1,2,1], [2,1,1]] Example 2: Input: nums = [1,2,3] Output: [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
Approach 1: Hashmap Create hashmap storing <number, count of numbers>. Then, perform backtracking if count > 0 by: (1) adding number, (2) backtrack, (3) remove number. class Solution { public: // Map storing <number, count> unordered_map<int, int> count; int size; void backtrack(vector<vector<int>>& result, vector<int>& curr) { if (curr.size() == size){ result.push_back(curr); return; } for (auto it = count.begin(); it != count.end(); it++) { // If count == 0, skip this number if (it->second == 0) continue; // Add number to current array curr.push_back(it->first); // Decrement count since we added // number to the current array it->second = it->second - 1; backtrack(result, curr); // Backtrack by removing number from current // array and incrementing count it->second = it->second + 1; curr.pop_back(); } } vector<vector<int>> permuteUnique(vector<int>& nums) { vector<vector<int>> result; vector<int> curr; size = nums.size(); // Count frequency of each number for(int i : nums) count[i]++; backtrack(result, curr); return result; } }; Approach 3: Sort And Skip Duplicates class Solution { public: ....void backtrack(vector<int> nums, vector<vector<int>>& result, int pos) { ........if (pos == nums.size() - 1) { ............result.push_back(nums); ............return; ........} ........ ........for (int i = pos; i < nums.size(); i++) { ............if (i != pos && nums[i] == nums[pos]) ................continue; ............ ............swap(nums[i], nums[pos]); ............backtrack(nums, result, pos + 1); ........} ....} .... ....vector<vector<int>> permuteUnique(vector<int>& nums) { ........vector<vector<int>> result; ........sort(nums.begin(), nums.end()); ........backtrack(nums, result, 0); ........return result; ....} }; Approach 2: Backtracking + Hashset Backtrack by swapping numbers in the array. To eliminate duplicates, use a hashset to determine if a number has already been swapped. class Solution { public: ....void recursion(vector<vector<int>> &res, ................ vector<int> num, int pos) { ........if (pos == num.size() - 1) { ............res.push_back(num); ............return; ........} ........ ........// Hashset to track which numbers ........// have already been swapped ........unordered_set<int> numset; ........ ........for (int i = pos; i < num.size(); i++) { ............// If num has already been swapped, skip it ............if (numset.find(num[i]) != numset.end()) ................continue; ............numset.insert(num[i]); ............// Swap numbers to permute num ............swap(num[pos], num[i]); ............recursion(res, num, pos+1); ........} ....} ....vector<vector<int> > permuteUnique(vector<int> &num) { ........vector<vector<int> >res; ........recursion(res, num, 0); ........return res; ....} };
158. Read N Characters Given read4 II - Call Multiple Times Given a file and assume that you can only read the file using a given method read4, implement a method read to read n characters. Your method read may be called multiple times. Method read4: The API read4 reads four consecutive characters from file, then writes those characters into the buffer array buf4. The return value is the number of actual characters read. Note that read4() has its own file pointer, much like FILE *fp in C. Example 1: Input: file = "abc", queries = [1,2,1] Output: [1,2,0] Explanation: The test case represents the following scenario: File file("abc"); Solution sol; sol.read(buf, 1); // After calling your read method, buf should contain "a". We read a total of 1 character from the file, so return 1. sol.read(buf, 2); // Now buf should contain "bc". We read a total of 2 characters from the file, so return 2. sol.read(buf, 1); // We have reached the end of file, no more characters can be read. So return 0. Assume buf is allocated and guaranteed to have enough space for storing all characters from the file
Approach 1: Internal/External Buffer Maintain internal and external buffers. While external buffer < n, byte-by-byte copy from internal to external buffer. If intBufPtr >= intBufSize, read4 new data. private: ....// Interval buffer to store data bet/ calls ....char buf4[4]; ....// Interval buffer ptr ....int intBufPtr4 = 0; ....// Interval buffer size ....int intBufSize4 = 0; .... public: ..../** .... * @param buf Destination buffer .... * @param n Number of characters to read .... * @return....The number of actual characters read .... * Descriptn Copy data from interval buf to external buf .... *............If interval buf runs out of data, .... *............then populate it first. .... */ ....int read(char *buf, int n) { ........// Ptr to external buf ........int extBufPtr = 0; ........ ........while (extBufPtr < n) { ............// Interval buffer runs out of data, ............// so trigger a new read4 call ............if (intBufPtr4 >= intBufSize4) { ................// Reset interval buf's ptr to the beginning ................intBufPtr4 = 0; ................ ................// Read 4 chars ................intBufSize4 = read4(buf4); ................ ................// If no more data, break ................if (intBufSize4 == 0) ....................break; ............} ............// Copy data from interval buf to external buf ............buf[extBufPtr++] = buf4[intBufPtr4++]; ........} ........ ........// Return num of copied chars to external buf ........return extBufPtr; ....} };
973. K Closest Points to Origin Given an array of points where points[i] = [xi, yi] represents a point on the X-Y plane and an integer k, return the k closest points to the origin (0, 0). The distance between two points on the X-Y plane is the Euclidean distance (i.e., √(x1 - x2)2 + (y1 - y2)2). You may return the answer in any order. The answer is guaranteed to be unique (except for the order that it is in). Example 1: Input: points = [[1,3],[-2,2]], k = 1 Output: [[-2,2]] Explanation: The distance between (1, 3) and the origin is sqrt(10). The distance between (-2, 2) and the origin is sqrt(8). Since sqrt(8) < sqrt(10), (-2, 2) is closer to the origin. We only want the closest k = 1 points from the origin, so the answer is just [[-2,2]]. Example 2: Input: points = [[3,3],[5,-1],[-2,4]], k = 2 Output: [[3,3],[-2,4]] Explanation: The answer [[-2,4],[3,3]] would also be accepted.
Approach 1: Map class Solution { public: ....vector<vector<int>> kClosest(vector<vector<int>>& points, int k) { ........vector<vector<int>> result; ........map<int, vector<int>> m; ........ ........// Calculate square difference from each point to origin (0,0) ........for (int i = 0; i < points.size(); i++) { ............int sqDiff = points[i][0] * points[i][0] + ........................ points[i][1] * points[i][1]; ............ ............// Add index to this hashmap's square difference ............m[sqDiff].push_back(i); ........} ........ ........// For each element in hashmap ........for (auto i = m.begin(); i != m.end() && k > 0; i++) { ............// Add the first k elements with the smallest square ............// difference to the result ............for (int j : i->second) { ................result.push_back(points[j]); ................k--; ............} ........} ........ ........return result; ....} }; Approach 2: Min Heap Time: O(K log N) Space: O(N) class Solution { private:.... ....struct compare { ........bool operator()(vector<int> &p, vector<int> &q) { ............// If the square distance of the current vector q is less ............// than the square distance of the previous vector p, ............// then move current vector q to top of min heap ............return p[0] * p[0] + p[1] * p[1] > ................ q[0] * q[0] + q[1] * q[1]; ........} ....}; .... public: ....vector<vector<int>> kClosest(vector<vector<int>>& points, int k) { ........priority_queue<vector<int>, vector<vector<int>>, compare> pq( ............points.begin(), points.end()); ........ ........// Append the top K elemens of min heap to result ........vector<vector<int>> result; ........while (!pq.empty() && k > 0) { ............result.push_back(pq.top()); ............pq.pop(); ............k--; ........} ........return result; ....} };
1249. Minimum Remove to Make Valid Parentheses Given a string s of '(' , ')' and lowercase English characters. Your task is to remove the minimum number of parentheses ( '(' or ')', in any positions ) so that the resulting parentheses string is valid and return any valid string. Formally, a parentheses string is valid if and only if: It is the empty string, contains only lowercase characters, or It can be written as AB (A concatenated with B), where A and B are valid strings, or It can be written as (A), where A is a valid string. Example 1: Input: s = "lee(t(c)o)de)" Output: "lee(t(c)o)de" Explanation: "lee(t(co)de)" , "lee(t(c)ode)" would also be accepted. Example 2: Input: s = "a)b(c)d" Output: "ab(c)d" Example 3: Input: s = "))((" Output: "" Explanation: An empty string is also valid. Example 4: Input: s = "(a(b(c)d)" Output: "a(b(c)d)"
Approach 1: Mark Invalid Parens Iterate forward through string and use counter to mark invalid closing parens. Iterate backwards through string and use counter to mark invalid closing parens. Then, build result string consisting of unmarked chars. class Solution { public: ....string minRemoveToMakeValid(string s) { ........// Remove invalid parens moving foward ........int count = 0; ........for (int i = 0; i < s.length(); i++) { ............if (s[i] == '(') { ................count++; ............} else if (s[i] == ')') { ................// If there's no opening parens to ................// complement this closing parens, ................// then mark this closing parens as ................// invalid. ................if (count == 0) ....................s[i] = '#'; ................else ....................count--; ............} ........} ........ ........// Remove invalid parens moving backward ........count = 0; ........for (int i = s.length() - 1; i >= 0; i--) { ............if (s[i] == ')') { ................count++; ............} else if (s[i] == '(') { ................if (count == 0) ....................s[i] = '#'; ................else ....................count--; ............} ........} ........ ........// Build result ........string result; ........for (char c : s) { ............if (c != '#') ................result.push_back(c); ........} ........return result; ....} };
143. Reorder List You are given the head of a singly linked-list. The list can be represented as: L0 → L1 → ... → Ln - 1 → Ln Reorder the list to be on the following form: L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → ... You may not modify the values in the list's nodes. Only nodes themselves may be changed. Example 1: Input: head = [1,2,3,4] Output: [1,4,2,3] Example 2: Input: head = [1,2,3,4,5] Output: [1,5,2,4,3]
Approach 1: Merge Forward and Reverse Lists 1) Find middle of list using slow/fast ptrs slow=[1,2,3] fast=[4,5,6] 2) Reverse second half of list slow=[1,2,3,4] fast=[6,5,4] 3) Merge first and second half of lists slow=[1,6,2,5,3,4] fast=[6,5,4] class Solution { public: ....void reorderList(ListNode* head) { ........ListNode *slow = head, *fast = head; ........ ........// Find the middle of the list ........// slow = [1,2,3] ........// fast = [4,5,6] ........while (fast && fast->next) { ............slow = slow->next; ............fast = fast->next->next; ........} ........ ........// Reverse the 2nd half of the list ........// slow = [1,2,3,4] ........// fast = [6,5,4] ........ListNode *prev = NULL, *curr = slow, *tmp; ........ ........while (curr) { ............tmp = curr->next; ............curr->next = prev; ............prev = curr; ............curr = tmp; ........} ........ ........// Merge 2 sorted lists ........// first = [1,6,2,5,3,4] ........ListNode *first = head, *second = prev; ........ ........while (second->next) { ............tmp = first->next; ............first->next = second; ............first = tmp; ............ ............tmp = second->next; ............second->next = first; ............second = tmp; ........} ....} };
247. Strobogrammatic Number II Given an integer n, return all the strobogrammatic numbers that are of length n. You may return the answer in any order. A strobogrammatic number is a number that looks the same when rotated 180 degrees (looked at upside down). Example 1: Input: n = 2 Output: ["11","69","88","96"] Example 2: Input: n = 1 Output: ["0","1","8"]
Approach 1: Recursion Only [0,1,6,8,9] can be rotated 180 deg. Use DFS recursion to build result. Handle the even (n % 2 == 0; return "") and odd (n%2 == 1; return [0,1,8]) base cases. DFS using recursion(m-2,n) and return vector<string>. Iterate through result array and add [0,1,6,8,9] as necessary. class Solution { public: ....vector<string> findStrobogrammatic(int n) { ........return helper(n , n); ....} .... ....vector<string> helper(int m, int n) { ........// If strobogrammatic num is even (n%2==0), then ........// return no numbers now and append even result ........// string length of digits later. ........// (ex. - "11", "69", "88", "96") ........if(m == 0) ............return vector<string>({""}); ........ ........// If strobogrammatic num is even (n%2==0), only ........// [0,1,8] can be rotated 180 deg. Append odd ........// result string length of digits later. ........// (ex. - "101", "609", "808", "906") ........if(m == 1) ............return vector<string>({"0", "1", "8"}); ........ ........// DFS down to odd/even base case (n%2) ........vector<string> tmp = helper(m - 2, n); ........ ........// Add strobogrammatic nums to the left and right ........// edges of the result string. ........vector<string> res; ........for(int i = 0; i < tmp.size(); i++) { ............// 0's cannot be added when m == n because "0110" ............// in invalid. Only add 0 to string result edges ............// when m != n. ............if(m != n) ................res.push_back("0" + tmp[i] + "0"); ............ ............// Add 1,6,8,9 to result string edges since they ............// can be rotated 180 deg. Ex. - "1691" or "6119" ............res.push_back("1" + tmp[i] + "1"); ............res.push_back("6" + tmp[i] + "9"); ............res.push_back("8" + tmp[i] + "8"); ............res.push_back("9" + tmp[i] + "6"); ........} ........ ........return res; ....} };
543. Diameter of Binary Tree Given the root of a binary tree, return the length of the diameter of the tree. The diameter of a binary tree is the length of the longest path between any two nodes in a tree. This path may or may not pass through the root. The length of a path between two nodes is represented by the number of edges between them. Example 1: Input: root = [1,2,3,4,5] Output: 3 Explanation: 3 is the length of the path [4,2,1,3] or [5,2,1,3]. Example 2: Input: root = [1,2] Output: 1
Approach 1: Recursion Recursively calculate height but update a length variable at the end of the dfs function. class Solution { public: ....int diameterOfBinaryTree(TreeNode* root) { ........int len = 0; ........dfs(root, len); ........return len; ....} .... ....int dfs(TreeNode* root, int &len) { ........if (!root) ............return 0; ........ ........int left = dfs(root->left, len); ........int right = dfs(root->right, len); ........ ........len = max(len, left + right); ........ ........return max(left, right) + 1; ....} };
Binary Tree Paths Given the root of a binary tree, return all root-to-leaf paths in any order. A leaf is a node with no children. Example 1: Input: root = [1,2,3,null,5] Output: ["1->2->5","1->3"] Example 2: Input: root = [1] Output: ["1"]
Approach 1: Recursion Traverse using DFS and append value to current string. If you reach a leaf node, then add the current string to the result. class Solution { private: ....vector<string> result; .... public: ....vector<string> binaryTreePaths(TreeNode* root) { ........dfs(root, ""); ........return result; ....} .... ....void dfs(TreeNode *root, string curr) { ........if (!root) ............return; ........ ........// Append val to current string ........curr += (!curr.empty() ? "->" : "") + to_string(root->val); ........ ........dfs(root->left, curr); ........dfs(root->right, curr); ........ ........// If this is a leaf node, add current ........// string to the result ........if (root && !root->left && !root->right) { ............result.push_back(curr); ............return; ........} ....} };
236. Lowest Common Ancestor of a Binary Tree Given a binary tree, find the lowest common ancestor (LCA) of two given nodes in the tree. According to the definition of LCA on Wikipedia: "The lowest common ancestor is defined between two nodes p and q as the lowest node in T that has both p and q as descendants (where we allow a node to be a descendant of itself)." Example 1: Input: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1 Output: 3 Explanation: The LCA of nodes 5 and 1 is 3. Example 2: Input: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4 Output: 5 Explanation: The LCA of nodes 5 and 4 is 5, since a node can be a descendant of itself according to the LCA definition. Example 3: Input: root = [1,2], p = 1, q = 2 Output: 1
Approach 1: Recursion class Solution { private: ....TreeNode* lca = NULL; .... public: ....TreeNode* lowestCommonAncestor( ........TreeNode* root, TreeNode* p, TreeNode* q) { ........dfs(root, p, q); ........return lca; ....} .... ....bool dfs(TreeNode* root, TreeNode* p, TreeNode* q) { ........if (!root) ............return NULL; ........ ........bool left = dfs(root->left, p, q); ........bool right = dfs(root->right, p, q); ........ ........// If current node matches p or q ........bool found = root->val == p->val || .................... root->val == q->val; ........ ........// If current node and one leaf node matches OR ........// if both leaf nodes match, then set LCA ........if ((found && (left || right)) || ............(left && right)) { ............lca = root; ............return false; ........} ........ ........// Return whether current node or ........// any leaf nodes match ........return found || left || right; ....} }; class Solution { public: ....TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) { ........// Base Case: If root==NULL or p/q was found, then return root ........if (!root || root->val == p->val || root->val == q->val) ............return root; ........ ........TreeNode *left = lowestCommonAncestor(root->left, p, q); ........TreeNode *right = lowestCommonAncestor(root->right, p, q); ........ ........if (!left) ............// If p or q was found in the right subtree, ............// then lca is in the right subtree. ............// NOTE: If q is in p's subtree, then p's parent node ............// will see parent->right==NULL (since q is not in the ............// parent's right subtree) and root==p will return ............// without traversing child nodes. But, since the problem ............// states "p and q will exist in the tree", then q must ............// be in p's subtree, so no need to traverse root==p's ............// child nodes. ............return right; ........else if (!right) ............// If p or q was found in the left subtree, ............// then lca is in the left subtree ............return left; ........else ............// If p and q was found in left and right subtree, ............// then lca is this root node ............return root; ....} };
138. Copy List with Random Pointer A linked list of length n is given such that each node contains an additional random pointer, which could point to any node in the list, or null. Construct a deep copy of the list. The deep copy should consist of exactly n brand new nodes, where each new node has its value set to the value of its corresponding original node. Both the next and random pointer of the new nodes should point to new nodes in the copied list such that the pointers in the original list and copied list represent the same list state. None of the pointers in the new list should point to nodes in the original list. For example, if there are two nodes X and Y in the original list, where X.random --> Y, then for the corresponding two nodes x and y in the copied list, x.random --> y. Return the head of the copied linked list. The linked list is represented in the input/output as a list of n nodes. Each node is represented as a pair of [val, random_index] where: val: an integer representing Node.val random_index: the index of the node (range from 0 to n-1) that the random pointer points to, or null if it does not point to any node. Your code will only be given the head of the original linked list. Example 1: Input: head = [[7,null],[13,0],[11,4],[10,2],[1,0]] Output: [[7,null],[13,0],[11,4],[10,2],[1,0]] Example 2: Input: head = [[1,1],[2,1]] Output: [[1,1],[2,1]] Example 3: Input: head = [[3,null],[3,0],[3,null]] Output: [[3,null],[3,0],[3,null]]
Approach 1: Recursion + Hash Map class Solution { private: ....unordered_map<Node*, Node*> visited; .... public:.... ....Node* copyRandomList(Node* head) { ........if (!head) ............return NULL; ........ ........// If the node has already been created, ........// return the existing node ........if (visited.count(head)) ............return visited[head]; ........ ........// If the node doesn't exist, create it ........Node *node = new Node(head->val); ........visited[head] = node; ........node->next = copyRandomList(head->next); ........node->random = copyRandomList(head->random); ........ ........return node; ....} };
680. Valid Palindrome II Given a string s, return true if the s can be palindrome after deleting at most one character from it. Example 1: Input: s = "aba" Output: true Example 2: Input: s = "abca" Output: true Explanation: You could delete the character 'c'. Example 3: Input: s = "abc" Output: false
Approach 1: Remove Left or Right Char If a differing char is found as you traverse left and right ptrs, then try removing either the left char and check if string is a valid palindrome. If not, then try removing right char and check if valid palindrome. class Solution { public: ....bool isPalindrome(string s, int left, int right) { ........while (left < right) { ............if (s[left++] != s[right--]) ................return false; ........} ........return true; ....} .... ....bool validPalindrome(string s) { ........int left = 0, right = s.length() - 1; ........ ........while (left < right) { ............// If left char != right char ............if (s[left] != s[right]) { ................// Check if deleting either the left char or ................// right char will yield a palindrome. ................// This works since only 1 char can be deleted ................// at most. ................return isPalindrome(s, left + 1, right) || .................... isPalindrome(s, left, right - 1); ............} ............left++; ............right--; ........} ........return true; ....} };
301. Remove Invalid Parentheses Given a string s that contains parentheses and letters, remove the minimum number of invalid parentheses to make the input string valid. Return all the possible results. You may return the answer in any order. Example 1: Input: s = "()())()" Output: ["(())()","()()()"] Example 2: Input: s = "(a)())()" Output: ["(a())()","(a)()()"] Example 3: Input: s = ")(" Output: [""]
Approach 1: Remove Subsequent Closing Parens + Reverse Remove Iterate through each char in string. If count < 0, then there is an extra closing parentheses. Remove the extra closing parens to make the string valid. Reverse string and swap '(' and ')' and call remove. This will remove any subsequent opening parentheses. class Solution { public: ....vector<string> removeInvalidParentheses(string s) { ........vector<string> result; ........remove(result, s, 0, 0, new char[] { '(', ')'}); ........return result; ....} .... ....void remove(vector<string>& result, string s, int last_i, int last_j, char paren[]) { ........int count = 0; ........for (int i = 0; i < s.length(); i++) { ............if (s[i] == paren[0]) ................count++; ............else if (s[i] == paren[1]) ................count--; ............ ............// If count == 0, it's a valid string. ............// If string is valid, skip removing parentheses. ............if (count >= 0) ................continue; ............ ............// last_j is the index of the last closing parens ............for (int j = last_j; j <= i; j++) { ................// If both current char is a closing parens and ................// (j == first index since the last count < 0 OR ................// previous char is not a closing parens) ................if (s[j] == paren[1] && ....................(j == last_j || s[j - 1] != paren[1])) { ....................// Remove the closing parens at s[j] ....................string str1 = s.substr(0, j) + ........................s.substr(j + 1, s.length()); .................... ....................// Remove close parens at s[j] and ....................// check the rest of the string for invalid parens ....................remove(result, str, i, j, paren); ................} ............} ............return; ........} ........ ........// Remove any opening parentheses by ........// reversing string and swapping '(' and ')'. ........// If paren[0] == '(', then call remove again to remove any ........// duplicate opening parens. Then, add the result on the ........// second call to remove with parens swapped. ........reverse(s.begin(), s.end()); ........if (paren[0] == '(') ............remove(result, s, 0, 0, new char[] { ')', '(' }); ........else ............result.push_back(s); ....} };
76. Minimum Window Substring Given two strings s and t of lengths m and n respectively, return the minimum window substring of s such that every character in t (including duplicates) is included in the window. If there is no such substring, return the empty string "". The testcases will be generated such that the answer is unique. A substring is a contiguous sequence of characters within the string. Example 1: Input: s = "ADOBECODEBANC", t = "ABC" Output: "BANC" Explanation: The minimum window substring "BANC" includes 'A', 'B', and 'C' from string t. Example 2: Input: s = "a", t = "a" Output: "a" Explanation: The entire string s is the minimum window. Example 3: Input: s = "a", t = "aa" Output: "" Explanation: Both 'a's from t must be included in the window. Since the largest window of s only has one 'a', return empty string.
Approach 1: Sliding Window 1) Initialize a vector called remaining, which contains the needed matching numbers of each character in s. 2) If there are stillcharacters needed to be contained (increment i in this case),decrease the matching number of that character and check if it isstill non-negative. If it is, then it is the character in t, sodecrease the total required number required. 3) If there is no morecharacters required (increment start in this case), record minand left if a smaller length is found. Recover the number of thischaracter in the remaining and if it is a character in tincrease required. class Solution { public: ....string minWindow(string s, string t) { ........int left = 0, right = 0, required = t.size(); ........int minLen = INT_MAX, minStart = 0; ........unordered_map<char, int> tmap; ........ ........// Create map of the count of required letters ........for (char c : t) ............tmap[c]++; ........ ........// For each right letter until the end of the string ........while (right <= s.length()) { ............// If there are any letters still required ............if (required) { ................// Break if this is the end of the string ................if (right == s.length()) ....................break; ................// Decrement count for this letter ................tmap[s[right]]--; ................// Decrement required total number of letters ................if (tmap[s[right]] >= 0) ....................required--; ................// Move to the next right char ................right++; ............} else { ................// If the current substring length < minLen, ................// update the substring ................if (right - left < minLen) { ....................minLen = right - left; ....................minStart = left; ................} ................ ................// Before we shift the left ptr right, ................// increment the current letter count. ................// Letters not in t will always have a negative ................// count in tmap, so only the required letters ................// in t will ever turn positive after incrementing ................// tmap[s[left]]. ................tmap[s[left]]++; ................// Increment total required letter count if any ................// required letter counts are > 0 in tmap ................if (tmap[s[left]] > 0) ....................required++; ................// Keep shifting the left ptr right until ................// there are letters required ................left++; ............} ........} ........return minLen == INT_MAX ? "" : s.substr(minStart, minLen); ....} };
567. Permutation in String Given two strings s1 and s2, return true if s2 contains a permutation of s1, or false otherwise. In other words, return true if one of s1's permutations is the substring of s2. Example 1: Input: s1 = "ab", s2 = "eidbaooo" Output: true Explanation: s2 contains one permutation of s1 ("ba"). Example 2: Input: s1 = "ab", s2 = "eidboaoo" Output: false
Approach 1: Sliding Window + Array as Hash Map Use array as <char, int> hash map, which maintains the current count of required letters. As the sliding window shifts right, decrement the letter count for the right letter since the right letter is no longer required since it is being added to the sliding window. Then, increment the letter count for the left letter since the left letter is now required since it is being removed from the sliding window. At any time, if the "required" letter count equals 0, then add the left index to result. class Solution { public: ....bool checkInclusion(string p, string s) { ........vector<int> result; ........ ........if (!s.length() || !p.length() || p.length() > s.length()) ............return 0; ........ ........// chmap is a <char, int> hash map that maintains ........// the current count for each letter ........vector<int> chmap(26, 0); ........int left = 0, right = 0; ........int required = p.length(); ........ ........for (char c : p) ............chmap[c - 'a']++; ........ ........// Start off with sliding window size 0. Then, shift ........// right until sliding window is size p.length(). ........// Then, keep shifting the window right and add left ........// index to result if number of required letters == 0. ........// l r ........// cbaebabacd ........// 0123456789 ........// a=0, b=0, c=0, required=0 ........while (right <= s.length()) { ............if (right == s.length()) ....................break; ............ ............// Decrement count of current letter ............chmap[s[right] - 'a']--; ............if (chmap[s[right] - 'a'] >= 0) ................required--; ............ ............// If no more letters required, add left index to result ............if (!required) ................result.push_back(left); ............ ............// Increment count of left letter since s[left] ............// will no longer be in the sliding window ............if (right - left + 1 == p.length()) { ................chmap[s[left] - 'a']++; ................if (chmap[s[left] - 'a'] > 0) ....................required++; ................left++; ............} ............ ............right++; ........} ........ ........return result.size() > 0; ....} };
438. Find All Anagrams in a String Given two strings s and p, return an array of all the start indices of p's anagrams in s. You may 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. Example 1: Input: s = "cbaebabacd", p = "abc" Output: [0,6] Explanation: The substring with start index = 0 is "cba", which is an anagram of "abc". The substring with start index = 6 is "bac", which is an anagram of "abc". Example 2: Input: s = "abab", p = "ab" Output: [0,1,2] Explanation: The substring with start index = 0 is "ab", which is an anagram of "ab". The substring with start index = 1 is "ba", which is an anagram of "ab". The substring with start index = 2 is "ab", which is an anagram of "ab".
Approach 1: Sliding Window + Array as Hash Map Use array as <char, int> hash map, which maintains the current count of required letters. As the sliding window shifts right, decrement the letter count for the right letter since the right letter is no longer required since it is being added to the sliding window. Then, increment the letter count for the left letter since the left letter is now required since it is being removed from the sliding window. At any time, if the "required" letter count equals 0, then add the left index to result. class Solution { public: ....vector<int> findAnagrams(string s, string p) { ........vector<int> result; ........ ........if (!s.length() || !p.length() || p.length() > s.length()) ............return result; ................ ........vector<int> chmap(26, 0); ........int left = 0, right = 0; ........int required = p.length(); ........ ........for (char c : p) ............chmap[c - 'a']++; ........ ........// Start off with sliding window size 0. Then, shift ........// right until sliding window is size p.length(). ........// Then, keep shifting the window right and add left ........// index to result if number of required letters == 0. ........// l r ........// cbaebabacd ........// 0123456789 ........// a=0, b=0, c=0, required=0 ........while (right <= s.length()) { ............if (right == s.length()) ....................break; ............ ............// Decrement count of current letter ............chmap[s[right] - 'a']--; ............if (chmap[s[right] - 'a'] >= 0) ................required--; ............ ............// If no more letters required, add left index to result ............if (!required) ................result.push_back(left); ............ ............// Increment count of left letter since s[left] ............// will no longer be in the sliding window ............if (right - left + 1 == p.length()) { ................chmap[s[left] - 'a']++; ................if (chmap[s[left] - 'a'] > 0) ....................required++; ................left++; ............} ............ ............right++; ........} ........ ........return result; ....} }; // SLIDING WINDOW APPROACH class Solution { public: ....vector<int> findAnagrams(string s, string p) { ........vector<int> result; ........ ........if (!s.length() || !p.length()) ............return result; ........ ........// Use vector since constraints say ........// alowercase ltrs only ........vector<int> count(26, 0); ........for (char c : p) ............count[c - 'a']++; ........ ........int left = 0, right = 0; ........int required = p.length(); ........ ........// Sliding window approach ........while (right <= s.length()) { ............if (required) { ................if (right == s.length()) ....................break; ................ ................count[s[right] - 'a']--; ................if (count[s[right] - 'a'] >= 0) ....................required--; ................right++; ............} else { ................if (right - left == p.length()) ....................result.push_back(left); ................ ................count[s[left] - 'a']++; ................if (count[s[left] - 'a'] > 0) ....................required++; ................left++; ............} ........} ........ ........return result; ....} };
340. Longest Substring with At Most K Distinct Characters Given a string s and an integer k, return the length of the longest substring of s that contains at most k distinct characters. Example 1: Input: s = "eceba", k = 2 Output: 3 Explanation: The substring is "ece" with length 3. Example 2: Input: s = "aa", k = 1 Output: 2 Explanation: The substring is "aa" with length 2.
Approach 1: Sliding Window + Hashmap. class Solution { public: ....int lengthOfLongestSubstringKDistinct(string s, int k) { ........unordered_map<char, int> count; ........int maxLen = 0; ........int left = 0; ........ ........// Iterate through each character ........for (int right = 0; right < s.length(); right++) { ............// Update count for current letter ............count[s[right]]++; ............ ............// If count > k, then update sliding window by ............// shifing left ptr right. Erase s[left] if current ............// letter is no longer in the sliding window. ............while (count.size() > k) { ................count[s[left]]--; ................if (count[s[left]] == 0) ....................count.erase(s[left]); ................left++; ............} ............ ............// Update max length ............// Since right-left+1 since index starts at 0 ............maxLen = max(maxLen, right - left + 1); ........} ........ ........return maxLen; ....} };
Single Number II Given an integer array nums where every element appears three times except for one, which appears exactly once. Find the single element and return it. You must implement a solution with a linear runtime complexity and use only constant extra space. Example 1: Input: nums = [2,2,3,2] Output: 3 Example 2: Input: nums = [0,1,0,1,0,1,99] Output: 99
Approach 1: Two Bit Arrays Observe that 0^x=x and x^x=0. If every element appears 2 times except for 1 (or even number of times except for 1), then we can just XOR each bit against an accumulator int. Every bit should be flipped to 0 except for the single number. If every element appears 3 times except for 1, we need 2 accumulator ints. The first time we see a bit for a number, we set seen1x[i]=1 and seen2x[i]=0, as shown below, and so forth for the 2x second and 3x third time shown below. Initial 1x 2x 3x 4x seen1x 0 1 0 0 1 seen2x 0 0 1 0 0 class Solution { public: ....int singleNumber(vector<int>& nums) { ........//........ Initial seenOnce seenTwice seenThree seenFour ........// seen1x.... 0........1........ 0........ 0........ 1 ........// seen2x.... 0........0........ 1........ 0........ 0 ........int seen1x[32] = {0}, seen2x[32] = {0}; ........ ........for (int num : nums) { ............for (int i = 0; i < 32; i++) { ................int bit = (num >> i) & 1; ................ ................/*if (bit) { ....................if (seen1x[i] == 0 && seen2x[i] == 0) { ........................seen1x[i] = 1; ....................} else if (seen1x[i] == 1 && seen2x[i] == 0) { ........................seen1x[i] = 0; ........................seen2x[i] = 1; ....................} else if (seen1x[i] == 0 && seen2x[i] == 1) { ........................seen2x[i] = 0; ....................} ................}*/ ................ ................// If bit is true and seen2x == 0, seen1x[i] ^= bit ................// Covers cases "if (seen1x[i] == 0 && seen2x[i] == 0)" & ................// "if (seen1x[i] == 1 && seen2x[i] == 0)" ................if (bit & (seen2x[i] ^ bit)) ....................seen1x[i] ^= bit; ................ ................// If bit is true and seen1x == 0, seen2x[i] ^= bit ................// Covers cases "if (seen1x[i] == 1 && seen2x[i] == 0)" & ................// if (seen1x[i] == 0 && seen2x[i] == 1) ................if (bit & (seen1x[i] ^ bit)) ....................seen2x[i] ^= bit; ............} ........} ........ ........// If sign bit [31] is negative, treat 0's as 1's, ........// then get complement ........// 11111111 11111111 11111111 11111101 ........// 00000000 00000000 00000000 00000010 ........// If sign bit is positive, treat 1's as 1's ........// 00000000 00000000 00000000 00000010 ........int result = 0; ........for (int i = 0; i < 31; i++) { ............if (seen1x[i] ^ seen1x[31]) { ................result += 1 << i; ............} ........} ........ ........// If negative (seen1x[31:31]=1), return complement ........// If positive, return result as-is ........return seen1x[31] ? ~result : result; ....} }; Approach 2: Optimized Bit Accumulator class Solution { public: ....int singleNumber(vector<int>& nums) { ........int seenOnce = 0, seenTwice = 0; ........ ........for (int num : nums) { ............// x = 2........ = 00000010 ............// If ~(seenTwice=0) and seenOnce=0, then seenOnce=1. ............// By setting "seenTwice = ~seenOnce", seenTwice ............// will be not set. ............// 1st: seenOnce = 00000010 ............//.... seenTwice = 00000000 ............// ............// If ~(seenTwice=0) and seenOnce=1, then seenOnce=0. ............// If ~(seenOnce=0) and seenTwice=0, then seenTwice=1. ............// 2nd: seenOnce = 00000000 ............//.... seenTwice = 00000010 ............// ............// If ~(seenTwice=1), then seenOnce=0. ............// If ~(seenOnce=0) and (seenTwice=1 ^ num=1), ............// then seenTwice=0. ............// 3rd: seenOnce = 00000000 ............//.... seenTwice = 00000000 ............// ............seenOnce = ~seenTwice & (seenOnce ^ num); ............seenTwice = ~seenOnce & (seenTwice ^ num); ........} ........ ........return seenOnce; ....} };
246. Strobogrammatic Number Given a string num which represents an integer, return true if num is a strobogrammatic number. A strobogrammatic number is a number that looks the same when rotated 180 degrees (looked at upside down). Example 1: Input: num = "69" Output: true Example 2: Input: num = "88" Output: true Example 3: Input: num = "962" Output: false Example 4: Input: num = "1" Output: true
Approach 1: Two Pointers class Solution { public: ....bool isStrobogrammatic(string num) { ........unordered_map<char, char> um = { ............{'0', '0'}, ............{'1', '1'}, ............{'6', '9'}, ............{'8', '8'}, ............{'9', '6'}, ........}; ........ ........int left = 0, right = num.length() - 1; ........ ........// Two Pointers: ........// If the complement of the left ptr != right ptr, ........// then string is not strobogrammatic ........while (left <= right) { ............if (um[num[left]] != num[right]) ................return false; ............left++; ............right--; ........} ........ ........return true; ....} };
977. Squares of a Sorted Array Given an integer array nums sorted in non-decreasing order, return an array of the squares of each number sorted in non-decreasing order. Example 1: Input: nums = [-4,-1,0,3,10] Output: [0,1,9,16,100] Explanation: After squaring, the array becomes [16,1,0,9,100]. After sorting, it becomes [0,1,9,16,100]. Example 2: Input: nums = [-7,-3,2,3,11] Output: [4,9,9,49,121]
Approach 1: Two Pointers class Solution { public: ....vector<int> sortedSquares(vector<int>& nums) { ........vector<int> result(nums.size()); ........ ........if (!nums.size()) ............return result; ........ ........int l = 0; ........int r = nums.size() - 1; ........ ........// Use 2 ptrs to traverse leftward and rightward ........// until all elements have calculated its square. ........for (int i = nums.size() - 1; i >= 0; i--) { ............int val = 0; ............if (abs(nums[l]) < abs(nums[r])) { ................val = nums[r]; ................r--; ............} else { ................val = nums[l]; ................l++; ............} ............result[i] = val * val; ........} ........ ........return result; ....} };
31. Next Permutation Implement next permutation, which rearranges numbers into the lexicographically next greater permutation of numbers. If such an arrangement is not possible, it must rearrange it as the lowest possible order (i.e., sorted in ascending order). The replacement must be in place and use only constant extra memory. Example 1: Input: nums = [1,2,3] Output: [1,3,2] Example 2: Input: nums = [3,2,1] Output: [1,2,3] Example 3: Input: nums = [1,1,5] Output: [1,5,1] Example 4: Input: nums = [1] Output: [1]
Approach 2: Single Pass Approach (1) Find the first decreasing number when traversing backwards (set to i). (2) Find smallest number larger than the first decreasing number (set to j). (3) Reverse the substring from i+1 to end of string class Solution { public: ....// Approach 2: Single Pass Approach ....void nextPermutation(vector<int>& nums) { ........// (1) Find the first decreasing number when ........// traversing backwards. ........//.... i ........// 1 5 8 4 7 6 5 3 1 ........int i = nums.size() - 2; ........while (i >= 0 && nums[i + 1] <= nums[i]) ............i--; ........ ........if (i >= 0) { ............// (2) Find smallest number larger than ............// the first decreasing number. ............//.... i.... j ............// 1 5 8 4 7 6 5 3 1 ............int j = nums.size() - 1; ............while (nums[j] <= nums[i]) ................j--; ............ ............//.... i.... j ............// 1 5 8 5 7 6 4 3 1 ............swap(nums[i], nums[j]); ........} .... ........// (3) Reverse the substring after i ........// 1 5 8 5 7 6 4 3 1 ........reverse(nums.begin() + i + 1, nums.end()); ....} };
157. Read N Characters Given Read4 Given a file and assume that you can only read the file using a given method read4, implement a method to read n characters. Method read4: The API read4 reads four consecutive characters from file, then writes those characters into the buffer array buf4. The return value is the number of actual characters read. Note that read4() has its own file pointer, much like FILE *fp in C. Definition of read4: Parameter: char[] buf4 Returns: int buf4[] is a destination, not a source. The results from read4 will be copied to buf4[]. Method read: By using the read4 method, implement the method read that reads n characters from file and store it in the buffer array buf. Consider that you cannot manipulate file directly. The return value is the number of actual characters read. Definition of read: Parameters: char[] buf, int n Returns: int buf[] is a destination, not a source. You will need to write the results to buf[]. Example 1: Input: file = "abc", n = 4 Output: 3 Explanation: After calling your read method, buf should contain "abc". We read a total of 3 characters from the file, so return 3. Note that "abc" is the file's content, not buf. buf is the destination buffer that you will have to write the results to. Example 4: Input: file = "leetcode", n = 5 Output: 5 Explanation: After calling your read method, buf should contain "leetc". We read a total of 5 characters from the file, so return 5.
Approach 2: Speed Up: No Internal Buffer Directly copy to the destination buffer. No need for an internal buffer, "char buf4[] = new char[4]()". int read(char *buf, int n) { ........int len = 4; ........int copiedChars = 0; ........ ........// While we still haven't copied all expected chars n ........// AND length=4 of last read4, read4 into buf+offset ........// and add length to offset ........while (copiedChars < n && len == 4) { ............len = read4(buf + copiedChars); ............copiedChars += len; ........} ........ ........// Return min of n or copiedChars ........// If copiedChars > n, limit to n since that's ........// the max chars the user requested ........return min(n, copiedChars); ....}
560. Subarray Sum Equals K Given an array of integers nums and an integer k, return the total number of continuous subarrays whose sum equals to k. Example 1: Input: nums = [1,1,1], k = 2 Output: 2 Example 2: Input: nums = [1,2,3], k = 3 Output: 2 Constraints: 1 <= nums.length <= 2 * 10^4 -1000 <= nums[i] <= 1000 -10^7 <= k <= 10^7
Approach 4: Hashmap Add up the sum as traversing nums from left to right. If sum == k, increment count. Secondly, we can remove a subarray from a large subarray to get target k. If the difference between the current sum and any previously calculated sum equals k, then increment count. If k=7, then 3+4+7+2-3+1=14. If you subtract 14-(num[2]=7)=7, then you get subarray 3+4+2-3+1=7. num = 3 4 7 2 -3 1 4 2 accum = 3 7 14 16 13 14 18 20 class Solution { public: ....// Add up the sum as traversing nums from left to right. ....// If you the difference between the current sum and any ....// previously calculated sum equals k, then increment ....// count. ....// If k=7, then 3+4+7+2-3+1=14. If you subtract ....// 14-(num[2]=7)=7, then you get subarray 3+4+2-3+1=7. ....// num = 3 4 7 2 -3 1 4 2 ....// accum = 3 7 14 16 13 14 18 20 ....int subarraySum(vector<int>& nums, int k) { ........int count = 0; // total count of subsets totaling k ........int sum = 0; // accumulator ........int diff; // current difference sum - k ........// Stores count for each subarray sum <sum, count> ........unordered_map<int, int> sumCount; ........ ........for (int i = 0; i < nums.size(); ++i) { ............// Add current num to accumulator ............sum += nums[i]; ............ ............// If sum == target k, increase result count ............if (sum == k) ................count++; ............ ............// Calc diff to check if there exists a prefix ............// subarray in the hashmap that we can remove ............// to total k ............diff = sum - k; ............ ............// If diff is in the hashmap, then add ............// hashmap count to total count ............if (sumCount.count(diff)) ................count += sumCount[diff]; ............ ............// Increment the current subarray sum ............sumCount[sum]++; ........}........ ........return count; ....} };
Binary Tree Right Side View Given the root of a binary tree, imagine yourself standing on the right side of it, return the values of the nodes you can see ordered from top to bottom. Example 1: Input: root = [1,2,3,null,5,null,4] Output: [1,3,4]
BFS Recursion Create vector<int> result and traverse using BFS. When a new level is reached, push a new int to result and keep updating result[level] = root->val. class Solution { private: ....vector<int> result; .... public: ....void bfs(TreeNode *root, int level) { ........if (!root) ............return; ........ ........if (level == result.size()) ............result.push_back(root->val); ........ ........bfs(root->right, level + 1); ........bfs(root->left, level + 1); ....} .... ....vector<int> rightSideView(TreeNode* root) { ........bfs(root, 0); ........return result; ....} }; BFS Iteration class Solution { public: ....vector<int> rightSideView(TreeNode* root) { ........vector<int> result; ........queue<TreeNode*> q; ........ ........if (!root) ............return result; ........ ........q.push(root); ........while (!q.empty()) { ............// Push rightmost node to result ............result.push_back(q.back()->val); ............ ............// Traverse through non-rightmost nodes ............// and then pop them off queue ............for (int i = q.size(); i > 0; i--) { ................TreeNode* node = q.front(); ................q.pop(); ................ ................if (node->left) ....................q.push(node->left); ................if (node->right) ....................q.push(node->right); ............} ........} ........ ........return result; ....} };
Subsets II Given an integer array nums that may contain duplicates, return all possible subsets (the power set). The solution set must not contain duplicate subsets. Return the solution in any order. Example 1: Input: nums = [1,2,2] Output: [[],[1],[1,2],[1,2,2],[2],[2,2]] Example 2: Input: nums = [0] Output: [[],[0]]
Backtracking class Solution { private: ....vector<vector<int>> subsets; ....vector<int> numsList; .... public: ....vector<vector<int>> subsetsWithDup(vector<int>& nums) { ........// Sort list to ignore duplicates ........sort(nums.begin(), nums.end()); ........numsList = nums; ........backtrack(0, vector<int>()); ........return subsets; ....} .... ....void backtrack(int idx, vector<int> current) { ........// Ending base case is controlled by for loop ........// When i == numsList.size(), return ........subsets.push_back(current); ........ ........// Calculate each permutation in the subset ........for (int i = idx; i < numsList.size(); i++) { ............// If this is a duplicate number, ignore ............if (i != idx && numsList[i] == numsList[i - 1]) ................continue; ............ ............// Simulate adding the number ............current.push_back(numsList[i]); ............ ............// Generate the next subset ............backtrack(i + 1, current); ............ ............// Simulate removing the number ............current.pop_back(); ........} ....} };
282. Expression Add Operators Given a string num that contains only digits and an integer target, return all possibilities to insert the binary operators '+', '-', and/or '*' between the digits of num so that the resultant expression evaluates to the target value. Note that operands in the returned expressions should not contain leading zeros. Example 1: Input: num = "123", target = 6 Output: ["1*2*3","1+2+3"] Explanation: Both "1*2*3" and "1+2+3" evaluate to 6.
Backtracking class Solution { public: ....void backtrack(vector<string>& result, string num, int target, int pos, long total, long multiply, string current) { ........if (pos == num.length()) { ............if (total == target) ................result.push_back(current); ............return; ........} ........ ........for (int i = pos; i < num.length(); i++) { ............// If this is not the first char in the digit && ............// the current digit starts with '0' ............if (i != pos && num[pos] == '0') ................break; ............ ............// Get digit in string and char format ............// If i != pos, concatenate digits together to form a larger number ............// ex. "123".substr(0, 1 - 0 + 1) = "12" ............string s_digit = num.substr(pos, i - pos + 1); ............long l_digit = stol(s_digit); ............ ............// If this is the first char in the digit ............if (pos == 0) { ................// Concatenate digits together ................backtrack(result, num, target, i + 1, l_digit, l_digit, current + s_digit); ............} else { // If this is not the first char in the digit ................// Add digit to current total ................backtrack(result, num, target, i + 1, total + l_digit, l_digit, current + "+" + s_digit); ................ ................// Subtract digit to current total ................backtrack(result, num, target, i + 1, total - l_digit, -l_digit, current + "-" + s_digit); ................ ................// Multiply digit to current total ................// We must subtract the previous operation since multiplication takes precedence over +/- ................// Therefore, we multiply using "total - multiply + multiply * digit" ................backtrack(result, num, target, i + 1, total - multiply + multiply * l_digit, multiply * l_digit, current + "*" + s_digit); ............} ........} ....} .... ....vector<string> addOperators(string num, int target) { ........vector<string> result; ........backtrack(result, num, target, 0, 0, 0, ""); ........return result; ....} };
393. UTF-8 Validation Given an integer array data representing the data, return whether it is a valid UTF-8 encoding. A character in UTF8 can be from 1 to 4 bytes long, subjected to the following rules: For a 1-byte character, the first bit is a 0, followed by its Unicode code. For an n-bytes character, the first n bits are all one's, the n + 1 bit is 0, followed by n - 1 bytes with the most significant 2 bits being 10. This is how the UTF-8 encoding would work: Char. number range | UTF-8 octet sequence (hexadecimal) | (binary) --------------------+--------------------------------------------- 0000 0000-0000 007F | 0xxxxxxx 0000 0080-0000 07FF | 110xxxxx 10xxxxxx 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx Note: The input is an array of integers. Only the least significant 8 bits of each integer is used to store the data. This means each integer represents only 1 byte of data. Example 1: Input: data = [197,130,1] Output: true Explanation: data represents the octet sequence: 11000101 10000010 00000001. It is a valid utf-8 encoding for a 2-bytes character followed by a 1-byte character. Example 2: Input: data = [235,140,4] Output: false Explanation: data represented the octet sequence: 11101011 10001100 00000100. The first 3 bits are all one's and the 4th bit is 0 means it is a 3-bytes character. The next byte is a continuation byte which starts with 10 and that's correct. But the second continuation byte does not start with 10, so it is invalid.
Bit Manipulation Let us look at what parts of a byte corresponding to an integer do we need to process. If it is the starting byte for a UTF-8 character, then we need to process the first NN bits where NN will be at max 4. Anything more than that and we would have an invalid character. In case the byte is a part of a UTF-8 character, then we simply need to check the first two bits or the most significant bits. The most significant bit needs to be a 1 and the second most significant bit needs to be a 0. class Solution { public: ....bool validUtf8(vector<int>& data) { ........int numBytes = 0; ........ ........for (int i = 0; i < data.size(); i++) { ............int num = data[i]; ............if (numBytes == 0) { ................if ((num >> 5) == 0b110) // 2 byte ....................numBytes = 1; ................else if ((num >> 4) == 0b1110) // 3 byte ....................numBytes = 2; ................else if ((num >> 3) == 0b11110) // 4 byte ....................numBytes = 3; ................else if (num >> 7) // 1 byte ....................// We've already checked 110xxxxx is not the case, ....................// which means only 8 bits exist in this UTF-8 ....................// encoding character, so only 0xxxxxxx is valid, ....................// we shift right 7 bits to see it is 0xxxxxxx or ....................// 1xxxxxxx, 1xxxxxxx means this encoding is invalid, ....................// because after shifted 7 bits it will be 00000001. ....................return false; ............} else { ................if ((num >> 6) != 0b10) ....................return false; ................numBytes--; ............} ........} ........return numBytes == 0; ....} }; class Solution { public: ....bool validUtf8(vector<int>& data) { ........// Number of bytes in the current UTF-8 char ........int numberOfBytesToProcess = 0; ........ ........// Masks to check 2 MSB's in a byte ........int mask1 = 1 << 7; ........int mask2 = 1 << 6; ........ ........// For each int in the data array ........for (int i = 0; i < data.size(); i++) { ............// If we start processing a new UTF-8 char ............if (numberOfBytesToProcess == 0) { ................// Count numberOfBytes in data array ................int mask = 1 << 7; ................while ((mask & data[i]) != 0) { ....................numberOfBytesToProcess++; ....................mask >>= 1; ................} ................ ................// If this is a 1 byte char, skip ................if (numberOfBytesToProcess == 0) ....................continue; ................ ................// Invalid scenarios according to the rules of the problem ................if (numberOfBytesToProcess > 4 || numberOfBytesToProcess == 1) ....................return false; ............} else { ................// Verify this octet sequence has MSB's set to '10' ................if (!((data[i] & mask1) != 0 && (data[i] & mask2) == 0)) ....................return false; ............} ............ ............// Reduce the number of bytes to process by 1 after each integer ............numberOfBytesToProcess--; ........} ........ ........// If we don't have complete data for a particular UTF-8 char ........return numberOfBytesToProcess == 0; ....} };
342. Power of Four Given an integer n, return true if it is a power of four. Otherwise, return false. An integer n is a power of four, if there exists an integer x such that n == 4x. Example 1: Input: n = 16 Output: true Example 2: Input: n = 5 Output: false
Bit Manipulation class Solution { public: ....bool isPowerOfFour(int n) { ........// Edge case n=0 ........if (!n) ............return false; ........ ........// Avoid int overflow when doing n-1 and n=INT_MIN ........long x = n; ........ ........// 0xaaaaaaaa=0b10101010 10101010 (powers of 2) (not power of 4) ........// 0x55555555=0b01010101 01010101 (powers of 4) ........// ........// ((x & (x - 1)) == 0): Removing rightmost 1-bit should equal 0 ........// If power of 4, only 1 bit should be set. ........// ........// ((x & 0x55555555): If x is a power of 4, then ........// "16 & (power of 4)" should equal be non-zero. ........// 00010000 & 10101010=1 ........return x > 0 && ((x & (x - 1)) == 0) && (x & 0x55555555); ....} };
Power of Two Given an integer n, return true if it is a power of two. Otherwise, return false. An integer n is a power of two, if there exists an integer x such that n == 2x. Example 1: Input: n = 1 Output: true Explanation: 20 = 1 Example 2: Input: n = 16 Output: true Explanation: 24 = 16
Bit Manipulation class Solution { public: ....bool isPowerOfTwo(int n) { ........// Edge case n=0 ........if (n == 0) ............return false; ........ ........// Prevent int overflow when doing x-1 ........long x = n; ........ ........// Power of 2 only has 1 bit. ........// Therefore, flipping this 1 bit results ........// in all bits being turned off. ........return (x & (x - 1)) == 0; ....} };
953. Verifying an Alien Dictionary In an alien language, surprisingly, they also use English lowercase letters, but possibly in a different order. The order of the alphabet is some permutation of lowercase letters. Given a sequence of words written in the alien language, and the order of the alphabet, return true if and only if the given words are sorted lexicographically in this alien language. Example 1: Input: words = ["hello","leetcode"], order = "hlabcdefgijkmnopqrstuvwxyz" Output: true Explanation: As 'h' comes before 'l' in this language, then the sequence is sorted. Example 2: Input: words = ["word","world","row"], order = "worldabcefghijkmnpqstuvxyz" Output: false Explanation: As 'd' comes after 'l' in this language, then words[0] > words[1], hence the sequence is unsorted. Example 3: Input: words = ["apple","app"], order = "abcdefghijklmnopqrstuvwxyz" Output: false Explanation: The first three characters "app" match, and the second string is shorter (in size.) According to lexicographical rules "apple" > "app", because 'l' > '∅', where '∅' is defined as the blank character which is less than any other character (More info).
Comparator class Solution { private: ....#define NUM_LETTERS 26 ....int cmap[NUM_LETTERS]; .... public: ....bool isAlienSorted(vector<string>& words, string order) { ........for (int i = 0; i < NUM_LETTERS; i++) ............cmap[order[i] - 'a'] = i; ........ ........// For each word, compare the current and previous words ........for (int i = 1; i < words.size(); i++) { ............// If compare returns > 0, then there is a difference ............// between word1 and word 2, so return false ............if (compare(words[i], words[i - 1]) > 0) ................return false; ........} ........ ........return true; ....} .... ....int compare(string word1, string word2) { ........int diff = 0; ........ ........// Iterate through word1 and word2 ........// If diff != 0, then there is a difference bet/ ........// word1 and word2, so exit loop ........for (int i = 0; i < word1.length() && ............ i < word2.length() && diff == 0;i++) { ............int c1 = cmap[word1[i] - 'a']; ............int c2 = cmap[word2[i] - 'a']; ............diff = c2 - c1; ........} ........ ........// If diff == 0, then there's no difference in letters up ........// to the common length of word1 and word2. However, word2 ........// can possibly be longer than word1, so return the length ........// difference when that happens. ........return diff == 0 ? word2.length() - word1.length() : diff; ....} };
133. Clone Graph Given a reference of a node in a connected undirected graph. Return a deep copy (clone) of the graph. Each node in the graph contains a value (int) and a list (List[Node]) of its neighbors. class Node { public int val; public List<Node> neighbors; } Test case format: For simplicity, each node's value is the same as the node's index (1-indexed). For example, the first node with val == 1, the second node with val == 2, and so on. The graph is represented in the test case using an adjacency list. An adjacency list is a collection of unordered lists used to represent a finite graph. Each list describes the set of neighbors of a node in the graph. The given node will always be the first node with val = 1. You must return the copy of the given node as a reference to the cloned graph. Input: adjList = [[2,4],[1,3],[2,4],[1,3]] Output: [[2,4],[1,3],[2,4],[1,3]] Explanation: There are 4 nodes in the graph. 1st node (val = 1)'s neighbors are 2nd node (val = 2) and 4th node (val = 4). 2nd node (val = 2)'s neighbors are 1st node (val = 1) and 3rd node (val = 3). 3rd node (val = 3)'s neighbors are 2nd node (val = 2) and 4th node (val = 4). 4th node (val = 4)'s neighbors are 1st node (val = 1) and 3rd node (val = 3).
DFS If Src Node Ptr is in hashmap, then return Dst Node Ptr. Else, then (1) create new Dst Node Ptr, (2) add to hashmap, and (3) add all of Src Node Ptr's neighbors to the new Dst Node Ptr's neighbor list. class Solution { private: ....// Stores <Src Node*, Dst Node*> ....unordered_map<Node*, Node*> um; .... public: ....Node* cloneGraph(Node* node) { ........if (!node) ............return NULL; ........ ........// If Src Node* is in the hashmap, ........// then return the Dst Node* ........auto itr = um.find(node); ........if (itr != um.end()) ............return itr->second; ........ ........// If Src Not* is not in the hashmap, ........// then create a new Dst Node* and ........// add it to the hashmap ........Node *newNode = new Node(node->val); ........um[node] = newNode; ........ ........// For each of the Src Node ptr's neighbors, ........// add the neighbor to the Dst Node ptr's ........// neighbor list ........for (Node* n : node->neighbors) ............newNode->neighbors.push_back(cloneGraph(n)); ........ ........return newNode; ....} };
161. One Edit Distance Given two strings s and t, return true if they are both one edit distance apart, otherwise return false. A string s is said to be one distance apart from a string t if you can: Insert exactly one character into s to get t. Delete exactly one character from s to get t. Replace exactly one character of s with a different character to get t. Example 1: Input: s = "ab", t = "acb" Output: true Explanation: We can insert 'c' into s to get t. Example 2: Input: s = "", t = "" Output: false Explanation: We cannot get t from s by only one step. Example 3: Input: s = "a", t = "" Output: true Example 4: Input: s = "", t = "A" Output: true
Delete-Insert-Replace Approach class Solution { public: ....bool isOneEditDistance(string s, string t) { ........int slen = s.length(); ........int tlen = t.length(); ........ ........// If s and t have a difference in length > 1, ........// then they cannot be one edit distance ........if (abs(slen - tlen) > 1) ............return false; ........ ........// If s and t are equal, they cannot be one edit distance ........if (s == t) ............return false; ........ ........// Iterate through initial matching chars bet/ s and t ........int i = 0, j = 0; ........while (i < slen && j < tlen && s[i] == t[j]) { ............i++; ............j++; ........} ........ ........if (slen > tlen) { ............// DELETION is only possible. ............// Check if the rest of the string matches ............// if we remove s[i]. ............// s="aacbb", t="aabb" ............// (slen=5) > (tlen=4) ............// (s.substr(2+1)="bb") == (t.substr(2)="bb") -> true ............return s.substr(i + 1) == t.substr(j); ........} else if (slen < tlen) { ............// INSERTION is only possible. ............// Check if the rest of the string matches ............// if we insert a char into s[i]. ............// s="aabb", t="aacbb" ............// (slen=4) > (tlen=5) ............// (s.substr(2)="bb") == (t.substr(2+1)="bb") -> true ............// If we inserted s[2]='c', then s==t. ............return s.substr(i) == t.substr(j + 1); ........} else { ............// REPLACING is only possible ............// s="aacbb", t="aadbb" ............// (slen=5) > (tlen=5) ............// (s.substr(2+1)="bb") == (t.substr(2+1)="bb") -> true ............// If we set s[i]='d', then s==t. ............return s.substr(i + 1) == t.substr(j + 1); ........} ....} };
Find the Duplicate Number Given an array of integers nums containing n + 1 integers where each integer is in the range [1, n] inclusive. There is only one repeated number in nums, return this repeated number. You must solve the problem without modifying the array nums and uses only constant extra space. Example 1: Input: nums = [1,3,4,2,2] Output: 2 Example 2: Input: nums = [3,1,3,4,2] Output: 3
Floyd's Tortoise and Hare Algorithm (Cycle Detection) After Phase 1: Fast vs Slow, we determine the intersection point of the fast and slow ptrs. In Phase 2: Slow vs Slow, let the distance from nums[0] to the start of the cycle be P, and the distance from nums[fast] (after phase 1) to the start of the cycle be x. The distance P from nums[0] to nums[cycleStart] equals x from nums[fast] to nums[cycleStart (i.e. P = x). Therefore, Phase 2 is executed until slow == slow2, at which point we find the cycle start. Time: O(n) Space: (1) class Solution { public: ....// Floyd's Algorithm (Cycle Detection) ....int findDuplicate(vector<int>& nums) { ........int slow = nums[0]; ........int fast = nums[0]; ........ ........// Find the intersection point of the slow ........// and fast ptrs (i.e. the idx right before ........// the start of the cycle) ........// Slow traverses 1 at a time. Fast traverses ........// 2 at a time. ........do { ............slow = nums[slow]; ............fast = nums[nums[fast]]; ........} while (slow != fast); ........ ........// Find the entrance to the cycle ........int slow2 = nums[0]; ........while (slow != slow2) { ............slow = nums[slow]; ............slow2 = nums[slow2]; ........} ........ ........return slow; ....} };
18. 4Sum (Four Sum) 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]]
Iterative Approach class Solution { public: ....vector<vector<int>> fourSum(vector<int>& nums, int target) { ........vector<vector<int>> result; ........ ........// If less than 4 nums, can't form any quadruplets ........if (nums.size() < 4) ............return result; ........ ........// Sort to ignore duplicate nums ........sort(nums.begin(), nums.end()); ........ ........// Iterate through first num ........for (int i = 0; i < nums.size() - 3; i++) { ............// Ignore duplicate nums ............if (i > 0 && nums[i] == nums[i - 1]) ................continue; ............ ............for (int j = i + 1; j < nums.size() - 2; j++) { ................// Ignore duplicate nums ................if (j > (i + 1) && nums[j] == nums[j - 1]) ....................continue; ................ ................for (int l = j + 1, r = nums.size() - 1; l < r;) { ....................// In order to prevent overflow, calculate ....................// sub_target and sum ....................int sub_target = target - nums[i] - nums[j]; ....................int sum = nums[l] + nums[r]; .................... ....................// If sum of nums[i] + nums[j] + nums[l] + nums[r] == target ....................if (sum == sub_target) { ........................// Add quadruplet to the result ........................result.push_back({ nums[i], nums[j], nums[l], nums[r] }); ........................ ........................// Move onto next left and right values ........................l++; ........................r--; ........................ ........................// Ignore duplicate nums ........................while (l < r && nums[l] == nums[l - 1]) ............................l++; ........................while (l < r && nums[r] == nums[r + 1]) ............................r--; ....................} else if (sum < sub_target) { ........................l++; ....................} else { ........................r--; ....................} ................} ............} ........} ........ ........return result; ....} };
203. Remove Linked List Elements Given the head of a linked list and an integer val, remove all the nodes of the linked list that has Node.val == val, and return the new head. Example 1: Input: head = [1,2,6,3,4,5,6], val = 6 Output: [1,2,3,4,5] Example 2: Input: head = [], val = 1 Output: [] Example 3: Input: head = [7,7,7,7], val = 7 Output: []
PreHead Approach class Solution { public: ....ListNode* removeElements(ListNode* head, int val) { ........if (!head) ............return NULL; ........ ........// Use prehead when need to delete head ........ListNode *preHead = new ListNode(); ........preHead->next = head; ........ListNode *prev = preHead; ........ListNode *curr = head; ........ ........while (curr) { ............if (curr->val == val) ................// Remove current node ................prev->next = curr->next; ............else ................// Set prev node only when not ................// deleting current node ................prev = curr; ............// Set next node ............curr = curr->next; ........} ........ ........return preHead->next; ....} };
Binary Tree Maximum Path Sum A path in a binary tree is a sequence of nodes where each pair of adjacent nodes in the sequence has an edge connecting them. A node can only appear in the sequence at most once. Note that the path does not need to pass through the root. The path sum of a path is the sum of the node's values in the path. Given the root of a binary tree, return the maximum path sum of any path. Input: root = [-10,9,20,null,null,15,7] Output: 42 Explanation: The optimal path is 15 -> 20 -> 7 with a path sum of 15 + 20 + 7 = 42.
Recursion Recursively calculate the left and right subtree max sum. For each node, we can either start a new path or continue the current path. The sum of the current node starting a new path is root->val + leftMaxSum + rightMaxSum, whereas continuing the current path is root->val + max(leftMaxSum, rightMaxSum). Then, update maxSum if current sum is greater. Lastly, recursively return the value if we continue the current path. class Solution { private: ....int maxSum = INT_MIN; .... public: ....int maxPathSumHelper(TreeNode* root) { ........if (!root) ............return 0; ........ ........// Max sum of the left and right subtrees of curr node ........int leftMaxSum = max(maxPathSumHelper(root->left), 0); ........int rightMaxSum = max(maxPathSumHelper(root->right), 0); ........ ........// Calculate sum of current subtree ........int currSum = root->val + leftMaxSum + rightMaxSum; ........ ........// Update sum if current subtree is greater than maxSum, ........// then update maxSum ........maxSum = max(maxSum, currSum); ........ ........// Return the max sum if continuing the same path ........return root->val + max(leftMaxSum, rightMaxSum); ....} .... ....int maxPathSum(TreeNode* root) { ........maxPathSumHelper(root);........ ........return maxSum; ....} };
938. Range Sum of BST Given the root node of a binary search tree and two integers low and high, return the sum of values of all nodes with a value in the inclusive range [low, high]. Input: root = [10,5,15,3,7,null,18], low = 7, high = 15 Output: 32 Explanation: Nodes 7, 10, and 15 are in the range [7, 15]. 7 + 10 + 15 = 32.
Recursion class Solution { public: ....void dfs(TreeNode* root, int low, int high, int &sum) { ........if (!root) ............return; ........ ........// If value is in range [low, high], add it ........if (low <= root->val && root->val <= high) ............sum += root->val; ........ ........// If current val is greater than low, then ........// check if there are values less than current val ........if (low < root->val) ............dfs(root->left, low, high, sum); ........ ........// If current val is less than high, then ........// check if there are values greater than current val ........if (root->val < high) ............dfs(root->right, low, high, sum); ....} .... ....int rangeSumBST(TreeNode* root, int low, int high) { ........int sum = 0; ........dfs(root, low, high, sum); ........return sum; ....} };
114. Flatten Binary Tree to Linked List Given the root of a binary tree, flatten the tree into a "linked list": The "linked list" should use the same TreeNode class where the right child pointer points to the next node in the list and the left child pointer is always null. The "linked list" should be in the same order as a pre-order traversal of the binary tree. Input: root = [1,2,5,3,4,null,6] Output: [1,null,2,null,3,null,4,null,5,null,6]
Recursively Attach Left Subtree to Right Subtree class Solution {.... public:.... ....void flatten(TreeNode* root) { ........if (!root) ............return; ........ ........flatten(root->left); ........flatten(root->right); ........ ........// Save right subtree ........TreeNode *rightSubtree = root->right; ........ ........// Root's right subtree = root's left subtree ........root->right = root->left; ........root->left = NULL; ........ ........// Traverse to previous root->right's ........// most rightmost subtree ........TreeNode *tmp = root; ........while (tmp->right) ............tmp = tmp->right; ........ ........// Attach root->right's rightmost subtree ........// to the previous root->right ........tmp->right = rightSubtree; ....} };
260. Single Number III Given an integer array nums, in which exactly two elements appear only once and all the other elements appear exactly twice. Find the two elements that appear only once. You can return the answer in any order. You must write an algorithm that runs in linear runtime complexity and uses only constant extra space. Example 1: Input: nums = [1,2,1,3,2,5] Output: [3,5] Explanation: [5, 3] is also a valid answer. Example 2: Input: nums = [-1,0] Output: [-1,0] Example 3: Input: nums = [0,1] Output: [1,0]
Steps: 1) Calculate bitmask 2) Find diff bit in bitmask 3) Use (num & diff_bit) to filter out nums with diff_bit ...bit set. Then, use x^x=0 property to filter out all ...nums except for the 1 num x. class Solution { public: ....vector<int> singleNumber(vector<int>& nums) { ........if (nums.size() == 2) ............return nums; ........ ........unsigned int bitmask = 0; ........ ........// Calculate XOR of the two unique nums ........// num ^= 1 -> 1 ........// num ^= 2 -> 3 ........// num ^= 1 -> 2 ........// num ^= 3 -> 1 ........// num ^= 2 -> 3 ........// num ^= 5 -> 6 = bitmask (0011 ^= 0101 -> 0110) ........for (int i : nums) ............bitmask ^= i; ........ ........// Extract rightmost 1-bit between x and y ........// 6 & (-6) = 2 = diffbit (0110 & 1010 = 0010) ........int diff_bit = bitmask & (-bitmask); ........ ........// Separate into 2 groups by doing (num & diff_bit): ........// diff_bit=1 and diff_bit=0 ........// ........// 2-bit=1 | 2-bit=0 ........// ---------|-------- ........// 2 (0010) | 1 (0001) ........// 2 (0010) | 1 (0001) ........// 3 (0011) | 5 (0101) ........// // Use x^x=0 property to filter out all nums in the 2-bit=1 group EXCEPT for the number x ........// 1 & 0010 = 0 ........// 2 & 0010 = 1 ((x=0) ^= 2 -> 2) ........// 1 & 0010 = 0 ........// 3 & 0010 = 1 ((x=2) ^= 3 -> 1) ........// 2 & 0010 = 1 ((x=1) ^= 2 -> 3) -> x=3 ........// 5 & 0010 = 0 ........int x = 0; ........for (int num : nums) ............// If (num & diff_bit) == 1, then num is in ............// 2-bit=1 group. ............if (num & diff_bit) ................x ^= num; ........ ........// (bitmask=6) ^ (x=3) = 5 ........// 0110 ^ 0011 = 0101 = 5 ........// Note that 3^5=6, 6^5=3, 6^3=5 ........return vector<int>({ x, x^((int)bitmask) }); ....} };
468. Validate IP Address Given a string queryIP, return "IPv4" if IP is a valid IPv4 address, "IPv6" if IP is a valid IPv6 address or "Neither" if IP is not a correct IP of any type. A valid IPv4 address is an IP in the form "x1.x2.x3.x4" where 0 <= xi <= 255 and xi cannot contain leading zeros. For example, "192.168.1.1" and "192.168.1.0" are valid IPv4 addresses but "192.168.01.1", while "192.168.1.00" and "[email protected]" are invalid IPv4 addresses. A valid IPv6 address is an IP in the form "x1:x2:x3:x4:x5:x6:x7:x8" where: 1 <= xi.length <= 4 xi is a hexadecimal string which may contain digits, lower-case English letter ('a' to 'f') and upper-case English letters ('A' to 'F'). Leading zeros are allowed in xi. For example, "2001:0db8:85a3:0000:0000:8a2e:0370:7334" and "2001:db8:85a3:0:0:8A2E:0370:7334" are valid IPv6 addresses, while "2001:0db8:85a3::8A2E:037j:7334" and "02001:0db8:85a3:0000:0000:8a2e:0370:7334" are invalid IPv6 addresses. Example 1: Input: queryIP = "172.16.254.1" Output: "IPv4" Explanation: This is a valid IPv4 address, return "IPv4". Example 2: Input: queryIP = "2001:0db8:85a3:0:0:8A2E:0370:7334" Output: "IPv6" Explanation: This is a valid IPv6 address, return "IPv6". Example 3: Input: queryIP = "256.256.256.256" Output: "Neither" Explanation: This is neither a IPv4 address nor a IPv6 address. Example 4: Input: queryIP = "2001:0db8:85a3:0:0:8A2E:0370:7334:" Output: "Neither" Example 5: Input: queryIP = "1e1.4.5.6" Output: "Neither"
String Split Approach class Solution { public: ....bool validateIPv4(string queryIP) { ........int start = 0, end = 0; ........int partCount = 0; ........ ........while (end != string::npos) { ............// Get next string token in IP address ............end = queryIP.find('.', start); ............string token = queryIP.substr(start, end - start); ............start += token.length() + 1; ............ ............if (token.empty() || token.length() > 3) ................return false; ............ ............// If not a digit, invalid ............for (char c : token) ................if (!isdigit(c)) ....................return false; ............ ............// If num is not in [0,255] or there's a ............// leading 0 to a digit, then invalid ............int num = stoi(token); ............if (num < 0 || num > 255 || ................(token[0] == '0' && token.length() > 1)) ................return false; ............ ............partCount++; ........} ........ ........// If there aren't 4 parts to the IP address, then invalid ........if (partCount != 4) ............return false; ........return true; ....} .... ....bool validateIPv6(string queryIP) { ........int start = 0, end = 0; ........int partCount = 0; ........ ........while (end != string::npos) { ............// Get next string token in IP address ............end = queryIP.find(':', start); ............string token = queryIP.substr(start, end - start); ............start += token.length() + 1; ............ ............if (token.empty() || token.length() > 4) ................return false; ............ ............// If not a hex address ............for (char c : token) ................if (!isxdigit(c)) ....................return false; ............ ............partCount++; ........} ........ ........// If there aren't 8 parts to this IPv6 address, ........// then invalid ........if (partCount != 8) ............return false; ........ ........return true; ....} .... ....string validIPAddress(string queryIP) { ........if (validateIPv4(queryIP)) return "IPv4"; ........if (validateIPv6(queryIP)) return "IPv6"; ........return "Neither"; ....} };
238. Product of Array Except Self Given an integer array nums, return an array answer such that answer[i] is equal to the product of all the elements of nums except nums[i]. The product of any prefix or suffix of nums is guaranteed to fit in a 32-bit integer. You must write an algorithm that runs in O(n) time and without using the division operation. Example 1: Input: nums = [1,2,3,4] Output: [24,12,8,6] Example 2: Input: nums = [-1,1,0,-3,3] Output: [0,0,9,0,0]
Suffix + Prefix Array public: ....vector<int> productExceptSelf(vector<int>& nums) { ........vector<int> result(nums.size()); ........ ........if (!nums.size()) ............return result; ........ ........// Calculate prefix/left array by traversing ........// from left to right. ........// num.... 1 2 3 4 ........// left....1 1 2 6 ........// right 24 12 4 1 ........// result 24 12 8 6 ........result[0] = 1; ........for (int i = 1; i < nums.size(); i++) { ............result[i] = nums[i - 1] * result[i - 1]; ........} ........ ........// Calculate suffix/right array and result by ........// traversing right to left. ........// -------- i=3 -------- ........// num.... 1 2 3 4 ........// result 1 1 2 6 ........// right............ 1 ........// -------- i=2 -------- ........// num.... 1 2 3 4 ........// result 1 1 8 6 ........// right........ 4 1 ........// -------- i=1 -------- ........// num.... 1 2 3 4 ........// result 1 12 8 6 ........// right.... 12 4 1 ........// -------- i=0 -------- ........// num.... 1 2 3 4 ........// result 24 12 8 6 ........// right 24 12 4 1 ........int right = 1; ........for (int i = nums.size() - 1; i >= 0; i--) { ............// Since result=nums[i-1]*left[i-1] already, ............// just multiply by right[i]. ............result[i] *= right; ............right *= nums[i]; ........} ........ ........return result; ....} };
269. Alien Dictionary There is a new alien language that uses the English alphabet. However, the order among the letters is unknown to you. You are given a list of strings words from the alien language's dictionary, where the strings in words are sorted lexicographically by the rules of this new language. Return a string of the unique letters in the new alien language sorted in lexicographically increasing order by the new language's rules. If there is no solution, return "". If there are multiple solutions, return any of them. A string s is lexicographically smaller than a string t if at the first letter where they differ, the letter in s comes before the letter in t in the alien language. If the first min(s.length, t.length) letters are the same, then s is smaller if and only if s.length < t.length. Example 1: Input: words = ["wrt","wrf","er","ett","rftt"] Output: "wertf" Example 2: Input: words = ["z","x"] Output: "zx" Example 3: Input: words = ["z","x","z"] Output: "" Explanation: The order is invalid, so return "".
Topological Sort + DFS 1) Initialize graph to empty set 2) When letters differ at the same index between 2 words, add that relationship to the graph (i.e. j->k in ["jf", "ke") 3) Topological sort using DFS 4) Reverse result and return class Solution { public: ....bool dfs(unordered_map<char, unordered_set<char>>& adj, ............ unordered_map<char, bool>& visited, ............ string &result, char c) { ........// If this node has been visited (i.e. visited contains the src key), ........// then return whether it is in the current path ........if (visited.count(c)) ............return visited[c]; ........ ........// visited[src]=false: The node has been visited before but is not ........// in the current path. ........// visited[src]=true: The node has been visited and is in the ........// current path. ........// visited.count(src)=0: The node has not been visited yet ........visited[c] = true; ........ ........// Visit all nodes in the graph along current path ........for (char neighbor : adj[c]) { ............if (dfs(adj, visited, result, neighbor)) ................return true; ........} ........ ........// Remove the node from the current path ........visited[c] = false; ........result += string(1, c); ........return false; ....} .... ....string topoSort(unordered_map<char, unordered_set<char>> adj) { ........string result; ........unordered_map<char, bool> visited; ........ ........// In DFS, nodes are returned once they either have no outgoing ........// links left, or all outgoing links have been visited. ........// Iterate through each node in adjacency list and append to ........// result whenever there's no more neighbors to visit. ........// If DFS returns true, then there was a loop was detected in ........// the graph. ........for (auto i : adj) { ............if (dfs(adj, visited, result, i.first)) ................return ""; ........} ........ ........// The adjacency list will return the result in reverse, ........// so reverse it to get output ........reverse(result.begin(), result.end()); ........ ........return result; ....} .... ....string alienOrder(vector<string>& words) { ........unordered_map<char, unordered_set<char>> adj; ........ ........// We use an unordered_set in ........// unordered_map<char, unordered_set<char>> because a letter can ........// point to multiple other letters ........for (string w : words) ............for (char c : w) ................adj[c] = unordered_set<char>(); ........ ........// Build adjacency list describing letter associations ........for (int word = 1; word < words.size(); word++) { ............string w1 = words[word - 1]; ............string w2 = words[word]; ............int commonLen = min(w1.length(), w2.length()); ............ ............// If chars match in w1 and w2 up to minLen and ............// w1.length > w2.length, then w1 > w2, which is invalid. ............if (w1.length() > w2.length() && w1.substr(0, commonLen) == w2) ................return ""; ............ ............// If the letters in w1 and w2 don't match, add that ............// relationship to revAdjList. After adding to the ............// adjacency list, break since only the first differing letter ............// matters in lexicographic order, the rest of the letters ............// in w1 and w2 don't mater. ............for (int c = 0; c < commonLen; c++) { ................if (w1[c] != w2[c]) { ....................adj[w1[c]].emplace(w2[c]); ....................break; ................} ............} ........} ........ ........// Topological sort ........return topoSort(adj); ....} };