diff --git a/.gitignore b/.gitignore index d99efa9..aa1d2cc 100644 --- a/.gitignore +++ b/.gitignore @@ -29,4 +29,7 @@ # Executables *.exe *.out -*.app \ No newline at end of file +*.app + +# Temp Codeforces Contest Env +CodeforcesContestRunner \ No newline at end of file diff --git a/Famous-Coding-Interview-Problems/JumpGame2.cpp b/Famous-Coding-Interview-Problems/JumpGame2.cpp index 14750f3..f160905 100644 --- a/Famous-Coding-Interview-Problems/JumpGame2.cpp +++ b/Famous-Coding-Interview-Problems/JumpGame2.cpp @@ -7,15 +7,13 @@ class Solution { int maxIndexReachable = nums[0]; int ans = 1, lim = nums[0]; - for(int i = 1; i < n; i++) - { + for(int i = 1; i < n; i++) { if(i > lim) { ans++; lim = maxIndexReachable; } maxIndexReachable = max(maxIndexReachable, i+nums[i]); } - return ans; } }; diff --git a/LeetCode/121.best-time-to-buy-and-sell-stock.cpp b/LeetCode/121.best-time-to-buy-and-sell-stock.cpp new file mode 100644 index 0000000..ebd217b --- /dev/null +++ b/LeetCode/121.best-time-to-buy-and-sell-stock.cpp @@ -0,0 +1,26 @@ +class Solution { +public: + int maxProfit(vector& prices) { + int n = prices.size(); + int ans = 0, suff_max = prices.back(); + for(int i = n-2; i >= 0; i--) { + ans = max(ans, suff_max - prices[i]); + suff_max = max(suff_max, prices[i]); + /* + for(int j = i+1; j < n; j++) { + ans = max(ans, prices[j] - prices[i]); + } + */ + } + return ans; + } +}; +/* + <---100---> +_ _ _ 120 _ _ _ _ _ _ + i + + max = 100 + */ + + diff --git a/LeetCode/1282.group-the-people-given-the-group-size-they-belong-to.cpp b/LeetCode/1282.group-the-people-given-the-group-size-they-belong-to.cpp new file mode 100644 index 0000000..cb6d854 --- /dev/null +++ b/LeetCode/1282.group-the-people-given-the-group-size-they-belong-to.cpp @@ -0,0 +1,29 @@ +class Solution { +public: + vector> groupThePeople(vector& groupSizes) { + int n = groupSizes.size(); + unordered_map> peopleInGroupSize = {}; + for(int i = 0; i < n; i++) { + int curSize = groupSizes[i]; + peopleInGroupSize[curSize].push_back(i); + } + vector> ans = {}; + for(auto [groupSize, people]: peopleInGroupSize) { + // start making groups of |groupSize| + vector cur = {}; + for(int i = 0; i < people.size(); i++) { + cur.push_back(people[i]); + if ( cur.size() == groupSize) { + ans.push_back(cur); + cur = {}; + } + } + } + return ans; + } +}; +/* +[group_size] --> [ids of people in it] +[3] --> [0,1,2,3,4,6] +[1] --> [5] + */ \ No newline at end of file diff --git a/LeetCode/1288.remove-covered-intervals.cpp b/LeetCode/1288.remove-covered-intervals.cpp new file mode 100644 index 0000000..2dff379 --- /dev/null +++ b/LeetCode/1288.remove-covered-intervals.cpp @@ -0,0 +1,30 @@ +using interval = vector; // length 2 +// [1, 3] and [1, 19] +// [1, 19] can contain [1, 3] +bool comparator(const interval &left, const interval &right) { + if(left[0] == right[0]) + return left[1] > right[1]; + return left[0] < right[0]; // asc order of starting time +} + +class Solution { +public: + int removeCoveredIntervals(vector& intervals) { + sort(intervals.begin(), intervals.end(), comparator); + int ans = intervals.size(); + + int maxEnd = 0; + + for(interval cur: intervals) { + // need to check if cur is already contained + int curEnd = cur[1]; + if (curEnd <= maxEnd) { + ans--; // throw away the current interval + } + + maxEnd = max(maxEnd, curEnd); + } + + return ans; + } +}; diff --git a/LeetCode/1302.deepest-leaves-sum.cpp b/LeetCode/1302.deepest-leaves-sum.cpp new file mode 100644 index 0000000..a1c3e27 --- /dev/null +++ b/LeetCode/1302.deepest-leaves-sum.cpp @@ -0,0 +1,31 @@ +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { + pair getDepthAndSum(TreeNode* root) { + if (root == NULL) return {0, 0}; + if (root->left == NULL and root->right == NULL) + return {1, root->val}; + + auto [left_depth, left_sum] = getDepthAndSum(root->left); + auto [right_depth, right_sum] = getDepthAndSum(root->right); + + if (left_depth == right_depth) + return {1 + left_depth, left_sum + right_sum}; + if (left_depth > right_depth) + return {1 + left_depth, left_sum}; + return {1 + right_depth, right_sum}; + } +public: + int deepestLeavesSum(TreeNode* root) { + return getDepthAndSum(root).second; + } +}; \ No newline at end of file diff --git a/LeetCode/1306.jump-game3.cpp b/LeetCode/1306.jump-game3.cpp new file mode 100644 index 0000000..4886804 --- /dev/null +++ b/LeetCode/1306.jump-game3.cpp @@ -0,0 +1,26 @@ +class Solution { + vector nums; + set s; // what all indices are there in recursion stack + + bool isPossible(int cur) { // can we reach a zero from cur index + if (s.find(cur) != s.end()) { + return false; // we detected a cycle / deadlock + } + if(0 <= cur && cur < nums.size()) { + if(nums[cur] == 0) return true; + s.insert(cur); + bool ans = false; + if (isPossible(cur + nums[cur])) ans = true; + else if (isPossible(cur - nums[cur])) ans = true; + s.erase(cur); + return ans; + } + return false; + } +public: + bool canReach(vector& arr, int start) { + //dp[i] <-- is it possible to reach a zero from i + nums = arr; + return isPossible(start); + } +}; diff --git a/LeetCode/1314.matrix-block-sum.cpp b/LeetCode/1314.matrix-block-sum.cpp new file mode 100644 index 0000000..2dad760 --- /dev/null +++ b/LeetCode/1314.matrix-block-sum.cpp @@ -0,0 +1,69 @@ +class Solution { +public: + vector> matrixBlockSum(vector>& mat, int k) { + int n = mat.size(), m = mat[0].size(); + vector> ans(n, vector(m, 0)); + vector> dp(n+1, vector(m+1, 0)); // 1-based indexing <-- prefix sums,˘ + + // compute the prefix sums + for(int i = 1; i <= n; i++) { + for(int j = 1; j <= m; j++) { + dp[i][j] = mat[i-1][j-1] + dp[i][j-1] + dp[i-1][j] - dp[i-1][j-1]; + } + } + + for(int i = 0; i < n; i++) { + for(int j = 0; j < m; j++) { + // compute the ans for (i,j) + int i1 = max(0, i-k), j1 = max(0,j-k); + int i2 = min(n-1, i+k), j2 = min(m-1, j+k); + i1++, i2++, j1++, j2++; //1-based indexing + + ans[i][j] = dp[i2][j2] - dp[i2][j1-1] - dp[i1-1][j2] + dp[i1-1][j1-1]; + } + },™ + return ans; + } +}; + +/* +prefix sum in 2d approach +dp[i][j] = sum of rect from (0,0) to (i,j) as diagnal points +=> it helps me in computing any rectangle sum in O(1) +(i1, j1) and (i2, j2) i1 < i2 and j1 < j2 + +dp[i2][j2] - dp[i1][j1-1] - dp[i1-1][j2] + dp[i1-1][j1-1] + + + +prefix sums can be used for each row individually +=> for given row, sum(j-k, j+k) => O(1) + j-k j j+k + + +i-k + + + +i x + + + +i+k + +(i,j) => O(k^2) +O(N^2k^2) +O(N^2 k) + + + + +k = 1 +[1,2,3], +[4,5,6], +[7,8,9] + +9*10/2 = 45 + + 5+6+8+9 = 28 +*/ diff --git a/LeetCode/1371.find-the-longest-substring-containing-vowels-in-even-counts.cpp b/LeetCode/1371.find-the-longest-substring-containing-vowels-in-even-counts.cpp new file mode 100644 index 0000000..774d42c --- /dev/null +++ b/LeetCode/1371.find-the-longest-substring-containing-vowels-in-even-counts.cpp @@ -0,0 +1,59 @@ +string vowels = "aeiou"; +class Solution { +public: + int findTheLongestSubstring(string s) { + int n = s.size(); + int ans = 0; + unordered_map> pref = {}; + for (char v: vowels) pref[v] = {0}; + + for(char cur: s) { + for(char v: vowels) { + int last_parity = *pref[v].rbegin(); + if (cur == v) pref[v].push_back(1 - last_parity); + else pref[v].push_back(last_parity); + } + } + + auto get_column = [&](int j) { // 1 based + int id = 0; + for(char v: vowels) { + int x = pref[v][j]; + id = 2*id + x; + } + return id; + }; + + int rightmost[33]; + rightmost[0] = 0; + for (int i = 1; i <= n; i++) { + int id = get_column(i); + rightmost[id] = i; + } + + for (int i = 1; i <= n; i++) { + // find the rightmost j substring(i, j) is valid + // ith column + int id = get_column(i-1); + int j = rightmost[id]; + if (j < i) continue; + ans = max(ans, j-i+1); + } + return ans; + } +}; + +/* +_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + i ^ ^ + maintain prefix count of all vowels pref[a][7] + a,b,a,e,e,a,e + i j +a - 0,1,1,0,0,0,1,1 +e - 0,0,0,0,1,0,0,1 +i - ...,1,.....,1 +o - ...,0,.....,1 +u - ...,0,.....,0 +10100 <-- 20 +n^2 substrings -> O(n) => overall O(n^3) +*/ \ No newline at end of file diff --git a/LeetCode/1402.reducing-dishes.cpp b/LeetCode/1402.reducing-dishes.cpp new file mode 100644 index 0000000..4acb0e4 --- /dev/null +++ b/LeetCode/1402.reducing-dishes.cpp @@ -0,0 +1,29 @@ +class Solution { +public: + int maxSatisfaction(vector& arr) { + int n = arr.size(); + sort(arr.begin(), arr.end()); + int ans = 0; + for(int i = 0; i < n; i++) { + int cur = 0; + // considering the suffix from pos i + // [arr[i], arr[i+1], ... arr[n-1]] + // 1 2 + for(int j = i; j < n; j++) { + cur += (j-i+1) * arr[j]; + } + ans = max(ans, cur); + } + return ans; + } +}; + +/* +a1 <= a2 <= a3 .... // we have proved +(a1,a2,...,ak) <-- reordering of satisfaction array + you can remove elements +max(a1 + 2*a2 + 3*a3 + k*ak) + + -9 -8 -1 0 5 + + how long a prefix would you remove to get the max score +*/ diff --git a/LeetCode/1409.queries-on-a-permutation-with-key.cpp b/LeetCode/1409.queries-on-a-permutation-with-key.cpp new file mode 100644 index 0000000..4c5b09e --- /dev/null +++ b/LeetCode/1409.queries-on-a-permutation-with-key.cpp @@ -0,0 +1,28 @@ +class Solution { +public: + vector processQueries(vector& queries, int m) { + unordered_map pos, rev_pos; // pos[3] - 10 => 3 occurs at index 10 + for(int i = 1; i <= m; i++) { + pos[i] = i-1, rev_pos[i-1] = i; + } + + vector ans = {}; + for(int q: queries) { + ans.push_back(pos[q]); + // increment the pos of all nos from 0 to pos[q]-1 + for (int i = pos[q]-1 ; i >= 0; i--) { + int cur = rev_pos[i]; + pos[cur] = i+1; // shift to right side + rev_pos[i+1] = cur; + } + pos[q] = 0; + rev_pos[0] = q; + } + return ans; + } +}; +// 1,2,3,4,5 +// 3,1,2,4,5 + +// _ _ _ _ _ _ _ _ _ _ _ + // ^ \ No newline at end of file diff --git a/LeetCode/1769.minimum-number-of-operations-to-move-all-balls-to-each-box.cpp b/LeetCode/1769.minimum-number-of-operations-to-move-all-balls-to-each-box.cpp new file mode 100644 index 0000000..a6f539c --- /dev/null +++ b/LeetCode/1769.minimum-number-of-operations-to-move-all-balls-to-each-box.cpp @@ -0,0 +1,37 @@ +class Solution { +public: + vector minOperations(string boxes) { + int n = boxes.size(); + int left_cnt = 0, tot_cnt = 0; // cnt of 1s + int left_sum = 0, tot_sum = 0; // sum of indices where its a 1 + + + for(int i = 0; i < n; i++) { + if (boxes[i] == '1') tot_cnt++, tot_sum += i; + } + + vector ans = {}; + for(int i = 0; i < n; i++) { + int right_cnt = tot_cnt - left_cnt; + int right_sum = tot_sum - left_sum; + + int left = left_cnt * i - left_sum; + int right = right_sum - right_cnt * i; + ans.push_back(left + right); + + if (boxes[i] == '1') left_cnt++, left_sum += i; + } + return ans; + } +}; + + +/* +i=13 +j<13 +i-j1 + i-j2 => 2*i - (j1+j2) + +j>13 +j1-i + j2-i => (j1+j2) - 2 *(i) +*/ + diff --git a/LeetCode/39.combination-sum.cpp b/LeetCode/39.combination-sum.cpp new file mode 100644 index 0000000..c9db32d --- /dev/null +++ b/LeetCode/39.combination-sum.cpp @@ -0,0 +1,32 @@ +using choice = vector; +vector arr = {}; + +// returning all possible choices to make target sum by using suffix of array [curIndex, ...] +vector getAllChoices(int curIndex, int target) { + // base case + if(target < 0) return {}; // no valid choice + if(target == 0) return {{}}; // one choice, and you chose nothing + if(curIndex == arr.size()) return {}; + + int curNumber = arr[curIndex]; + + vector ans = getAllChoices(curIndex+1, target); // curNumber is not used at all + + vector other = getAllChoices(curIndex, target - curNumber); // using it once + for(choice c: other) { + c.push_back(curNumber); + // now c is a valid choice + ans.push_back(c); + } + + return ans; +} + +class Solution { + +public: + vector combinationSum(vector& candidates, int target) { + arr = candidates; + return getAllChoices(0, target); + } +}; diff --git a/LeetCode/45.jump-game2.cpp b/LeetCode/45.jump-game2.cpp new file mode 100644 index 0000000..5eb0784 --- /dev/null +++ b/LeetCode/45.jump-game2.cpp @@ -0,0 +1,35 @@ +class Solution { +public: + int jump(vector& nums) { + int n = nums.size(); + vector dp(n, INT_MAX - 1); + // dp[i] = min steps to reach the end of array if we are at ith index + dp[n-1] = 0; + for(int i = n-2; i >= 0; i--) { + for(int j = i+1; j <= i+nums[i]; j++) { + if(j >= n) break; + dp[i] = min(dp[i], 1 + dp[j]); + } + } + + return dp[0]; + } +}; + +/* +Find: min steps to reach the end of array + +Given: i -> we can jump a length of nums[i] +0 index + +_ _ _ _ 7 _ _ _ _ _ _ _ _ _ + i x x x x x x x + +dp[i] = min steps to reach the end of array if we are at ith index + +for(j=i+1; j<=i+7; j++) { + dp[i] = min(dp[i], 1 + dp[j]); +} + +return dp[0] +*/ diff --git a/LeetCode/476.number-complement.cpp b/LeetCode/476.number-complement.cpp new file mode 100644 index 0000000..bf3caa9 --- /dev/null +++ b/LeetCode/476.number-complement.cpp @@ -0,0 +1,9 @@ +class Solution { +public: + int bitwiseComplement(int n) { + if(n == 0) return 1; + int numberOfBits = log2(n) + 1; // 100 log10(100) => 2+1 => 3 + int mask = (1 << numberOfBits) - 1; // pow(2, numberOfBits) + return mask ^ n; + } +}; diff --git a/LeetCode/53.maximum-subarray.cpp b/LeetCode/53.maximum-subarray.cpp new file mode 100644 index 0000000..019d5d2 --- /dev/null +++ b/LeetCode/53.maximum-subarray.cpp @@ -0,0 +1,27 @@ +class Solution { +public: + int maxSubArray(vector& nums) { + int n = nums.size(); + int ans = INT_MIN; + + // vector dp(n+1, 0); // O(N) extra space + // dp[i] = max subarray sum starting from index i + // mandate to pick something + int nextMax = 0; + for(int i = n-1; i >= 0; i--) { + // dp[i] = max(nums[i] + dp[i+1], 0) + // dp[i] = nums[i] + max(dp[i+1], 0); + int curMax = nums[i] + max(nextMax, 0); + ans = max(ans, curMax); + nextMax = curMax; + } + + return ans; + } +}; + +/* +_ _ _ _ _ 100 _ _ _ _ _ + i ^ + dp[i] = max(nums[i] + dp[i+1], 0) +*/ diff --git a/LeetCode/532.k-diff-pairs-in-an-array.cpp b/LeetCode/532.k-diff-pairs-in-an-array.cpp new file mode 100644 index 0000000..eda9324 --- /dev/null +++ b/LeetCode/532.k-diff-pairs-in-an-array.cpp @@ -0,0 +1,21 @@ +using hashmap = unordered_map; + +class Solution { +public: + int findPairs(vector& nums, int k) { + hashmap cnt; + for(int x: nums) cnt[x]++; + + int ans = 0; + for(auto p: cnt) { // iterating on unique numbers of the array + int x = p.first; + // check x+k exists in the array + if(cnt.find(x+k) == cnt.end()) { + continue; + } + ans += (k==0) ? cnt[x+k] >= 2 : cnt[x+k] >= 1; + } + + return ans; + } +}; diff --git a/LeetCode/542.01-matrix.cpp b/LeetCode/542.01-matrix.cpp new file mode 100644 index 0000000..1300106 --- /dev/null +++ b/LeetCode/542.01-matrix.cpp @@ -0,0 +1,63 @@ +using loc = pair; +int dx[] = {1, -1, 0, 0}; +int dy[] = {0, 0, 1, -1}; +class Solution { +public: + vector> updateMatrix(vector>& mat) { + int n = mat.size(), m = mat[0].size(); + + vector> dis(n, vector(m, INT_MAX)); + // dis[i][j] = nearest distance (i, j) to nearest 0 + + queue q; + for(int i = 0; i < n; i++) { + for(int j = 0; j < m; j++) { + if (mat[i][j] == 0) { + q.push({i, j}); + dis[i][j] = 0; + } + } + } + + while(!q.empty()) { + // loc cur = q.front(); + // int x = cur.first, y = cur.second; + auto [x, y] = q.front(); // current loc in mat, structured binding in C++ + q.pop(); + // (2,3) -> (1, 3) up, (3, 3) down, +1 -1 on the columns as well + for(int k = 0; k < 4; k++) { + int nx = x + dx[k], ny = y + dy[k]; + if (0 <= nx && nx < n && 0 <= ny && ny < m) { + // valid neighbour + if (dis[nx][ny] == INT_MAX) { + dis[nx][ny] = 1 + dis[x][y]; + q.push({nx, ny}); + } + } + } + } + + return dis; + } +}; + +/* +// BFS gives the shortest path in unweighted graphs + +n * m <--- 0s and 1s + + for every 1: + compute the smallest distance to 0 + +dis[i][j] = 0 where mat[i][j] = 0 + +queue<> Q = {(i,j)} where mat[i][j] = 0; + +cur = Q.front(); + +for(nei in neighbors(cur)) { + dis[nei] = 1 + dis[cur] if nei is not alreaady in queue +} + +*/ + diff --git a/LeetCode/55.jump-game.cpp b/LeetCode/55.jump-game.cpp new file mode 100644 index 0000000..22c9ef7 --- /dev/null +++ b/LeetCode/55.jump-game.cpp @@ -0,0 +1,30 @@ +class Solution { +public: + bool canJump(vector& nums) { + int n = nums.size(); + vector allowed(n, 0); // O(n) extra space + allowed[0] = 1; + for (int i = 0; i < n; i++) { + if (allowed[i]) { + for(int j = min(n-1, i+nums[i]); j >= i+1; j--) { + if(allowed[j]) break; + allowed[j] = 1; + } + } + } + return allowed[n-1]; + } +}; + +/* +_ _ _ 7 _ _ 1 1 1 1 1 _ + i x x x x x x x + +if i is allowerd and 100 + i+1,i+2,...,i+100 <-- allowed + +whether n-1 is allowed <-- true / false + + */ + + diff --git a/LeetCode/647.panlindrmoic-substrings.cpp b/LeetCode/647.panlindrmoic-substrings.cpp new file mode 100644 index 0000000..3f95980 --- /dev/null +++ b/LeetCode/647.panlindrmoic-substrings.cpp @@ -0,0 +1,39 @@ +class Solution { +public: + int countSubstrings(string s) { + int n = s.size(); + vector> dp(n, vector(n, 0)); + for(int i = 0; i < n; i++) + dp[i][i] = 1; + + // fill this dp + for(int len = 2; len <= n; len++) { + for(int i = 0; i + len - 1 < n; i++) { + // starting from i, and length len + int j = i + len - 1; + if (i+1 == j) { + dp[i][j] = s[i] == s[j]; + } + else { + dp[i][j] = s[i] == s[j] && dp[i+1][j-1]; + } + } + } + + int ans = 0; + for(int i = 0; i < n; i++) + for(int j = 0; j < n; j++) + ans += dp[i][j]; + return ans; + } +}; +/* +for substring in all_subtrings; + if palindrome(substring) + ans++; + + +dp[i][j] = substring(i, i+1, ..., j) = is this a palindrome + +s[i] == s[j] && dp[i+1][j-1] should be true +*/ \ No newline at end of file diff --git a/LeetCode/765.couples-holding-hands.cpp b/LeetCode/765.couples-holding-hands.cpp new file mode 100644 index 0000000..ec357cf --- /dev/null +++ b/LeetCode/765.couples-holding-hands.cpp @@ -0,0 +1,69 @@ +const int N = 70; +set g[N]; +bool vis[N]; + +void fill_cluster_size(int u, int &cluster_size) { + vis[u] = 1; + // cout << "dfs::at couple " << u << endl; + cluster_size++; + for(int v: g[u]) { + if(!vis[v]) { + fill_cluster_size(v, cluster_size); + } + } +} + +int get_couple_id(int person) { + return person / 2; +} + + +class Solution { +public: + int minSwapsCouples(vector& row) { + int n = row.size() / 2; + // normalizing the seating arrangement in terms of couple ids + for(int &x: row) x = get_couple_id(x); + + for(int i = 0; i < n; i++) { + g[i].clear(); + vis[i] = 0; + } + + for(int i = 0; i < row.size(); i += 2) { + int c1 = row[i], c2 = row[i+1]; + if( c1 == c2 ) continue; + g[c1].insert(c2); + g[c2].insert(c1); + // cout << i << " adding edge in couple " << c1 << " " << c2 << endl; + } + + int ans = 0; + for(int i = 0; i < n; i++) { + if(!vis[i]) { + int cluster_size = 0; + fill_cluster_size(i, cluster_size); + ans += cluster_size - 1; + } + } + return ans; + } +}; +/* + 0,3,1,2 -> 0,1,3,2 + easy notation: 0,1,0,1 + - Find a swap that can make two couples happy. + - +(0, 1) --- 1st couple --- couple id = 0 +(2, 3) --- 2nd couple --- couple id = 1 +(4, 5) -- 3rd couple --- couple id = 2 + 0,3,5,2,1,4 --> 0,1,2,1,0,2 + + 0---1---2 + \______/ + +x----y <--- 1 swap +x----y----z <--- 2 swaps + +C couples --- C-1 swaps +*/ diff --git a/LeetCode/797.all-paths-from-source-to-target.cpp b/LeetCode/797.all-paths-from-source-to-target.cpp new file mode 100644 index 0000000..d7b9868 --- /dev/null +++ b/LeetCode/797.all-paths-from-source-to-target.cpp @@ -0,0 +1,51 @@ +const int N = 20; +vector g[N]; +using path = vector; +set get_all_paths(int src, int tar) { + // cout << src << endl; + if(src == tar) return { {tar} }; + set ans = {}; + for(int v: g[src]) { + auto rem_paths = get_all_paths(v, tar); + for (path p: rem_paths) { + p.push_back(src); + ans.insert(p); + } + } + return ans; +} + + +class Solution { + +public: + + vector> allPathsSourceTarget(vector>& graph) { + // paths from 0 to 4 + // iterate on children v of 0 + // find paths from child v to 4 + // [0,1,3,4] + int n = graph.size(); + + if(n == 0) return {}; + for(int i = 0; i < n; i++) g[i].clear(); + + for(int i = 0; i < n; i++) { + for(int v: graph[i]) { + g[i].push_back(v); + } + } + + vector ans = {}; + set paths = get_all_paths(0, n-1); + + + // O(# of paths * avg_size of path) + for(auto p: paths) { + reverse(p.begin(), p.end()); + ans.push_back(p); + } + + return ans; + } +}; diff --git a/LeetCode/841.keys-and-room.cpp b/LeetCode/841.keys-and-room.cpp new file mode 100644 index 0000000..8ed1768 --- /dev/null +++ b/LeetCode/841.keys-and-room.cpp @@ -0,0 +1,33 @@ +class Solution { +public: + bool canVisitAllRooms(vector>& rooms) { + int n = rooms.size(); + vector vis(n, 0); + + queue q; + q.push(0); + vis[0] = 1; + while(!q.empty()) { + int cur = q.front(); + q.pop(); + for(int child: rooms[cur]) { + if (!vis[child]) { + vis[child] = 1; + q.push(child); + } + } + } + for(int i = 0; i < n; i++) { + if(!vis[i]) return 0; + } + return 1; + } +}; + +/* +Input: [[1,3],[3,0,1],[2],[0]] +0 --> 1 +| +| +3 +*/ diff --git a/LeetCode/877.stone-game.cpp b/LeetCode/877.stone-game.cpp new file mode 100644 index 0000000..2374848 --- /dev/null +++ b/LeetCode/877.stone-game.cpp @@ -0,0 +1,63 @@ +#define deb(x1, x2, x3) cout << #x1 << "=" << x1 << " " << #x2 << "=" << x2 << " "<< #x3 << "=" << x3 << endl; + +class Solution { +public: + bool stoneGame(vector& piles) { + int n = piles.size(); + // dp[i][j] = max profit for first player when the game is at state [i..j] + vector> dp(n, vector(n, 0)); + for(int i = 0; i < n; i++) { + dp[i][i] = piles[i]; // 1 size subarrays have been computed + // if(i+1 < n) { + // dp[i][i+1] = abs(piles[i] - piles[i+1]); // subarrays of size 2 + // } + } + for(int len = 2; len <= n; len++) { + for(int i = 0; i < n; i++) { + int j = i + len - 1; + if(j >= n) continue; + // i .. j + // take the Lth stone + int choice1 = piles[i] - dp[i+1][j]; + + // take the Rth stone + int choice2 = piles[j] - dp[i][j-1]; + dp[i][j] = max(choice1, choice2); + // cout << i << " " << j << " " << dp[i][j] << endl; + // deb(i, j, dp[i][j]); + } + } + + + return dp[0][n-1] > 0; + } +}; + +/* +5, 3, 4, 5 -> 3,4,5 -> 3,4 -> 3 + + 5 + <---------------------->17 ==> 17 - 5 = 12 + 23,....................,17 + 23<----------------------> ===> 23-7 = 16 + 7 + + +state = [L, R] => by how much quantity the first player wins + + +[0, n-1] => +ve => first player can win -> true +[0, n-1] => -ve => first player cant win -> false + +// take the Lth stone +choice1 = piles[L] - win(L+1, R) + +// take the Rth stone +choice2 = piles[R] - win(L, R-1) + +win(L, R) = max(choice1, choice2); + +return win(0, n-1) > 0 + +*/ + diff --git a/LeetCode/878.nth-magical-number.cpp b/LeetCode/878.nth-magical-number.cpp new file mode 100644 index 0000000..b228333 --- /dev/null +++ b/LeetCode/878.nth-magical-number.cpp @@ -0,0 +1,21 @@ +int countMultiples(long long x, long long a, long long b) { + // get # of multiples of a or b in range [1, x] + long long lcm = a * b / __gcd(a, b); + return x/a + x/b - x/lcm; +} + +class Solution { +public: + int nthMagicalNumber(int n, int a, int b) { + // a = 2, b = 3 in our example + long long lo = 1, hi = min(a, b) * 1LL * n, mod = 1e9 + 7; + while(lo < hi) { + long long mid = lo + (hi - lo) / 2; + if (countMultiples(mid, a, b) < n) + lo = mid + 1; + else + hi = mid; + } + return hi % mod; + } +}; diff --git a/LeetCode/878.nth-magical-number.py b/LeetCode/878.nth-magical-number.py new file mode 100644 index 0000000..c42e1c4 --- /dev/null +++ b/LeetCode/878.nth-magical-number.py @@ -0,0 +1,20 @@ +import math + +def countMultiples(x, a, b): + '''returns # of multiples of a or b in range [1, x]''' + lcm = a * b // math.gcd(a, b) + return x//a + x//b - x//lcm # x/2 + x/3 - x/6 + +class Solution: + def nthMagicalNumber(self, n: int, a: int, b: int) -> int: + # a = 2, b = 3 in our case + lo, hi = 1, min(a, b) * n # hi = 2*n remember? + while lo < hi: + mid = (lo + hi) >> 1 + if countMultiples(mid, a, b) < n: + lo = mid + 1 + else: + hi = mid + + return hi % (10**9 + 7) + diff --git a/LeetCode/890.find-and-replace-patterns.cpp b/LeetCode/890.find-and-replace-patterns.cpp new file mode 100644 index 0000000..934033e --- /dev/null +++ b/LeetCode/890.find-and-replace-patterns.cpp @@ -0,0 +1,45 @@ +class Solution { + bool matches(string word, string pattern) { + int n = word.size(); + vector forward(26, -1), backward(26, -1); + // map forward, backward; unordered_map + for(int i = 0; i < n; i++) { + int x = word[i] - 'a', y = pattern[i] - 'a'; + // I am trying to map x to y + if(forward[x] != -1 && forward[x] != y) return false; + if(backward[y] != -1 && backward[y] != x) return false; + forward[x] = y; + backward[y] = x; + } + + return true; + } + +public: + vector findAndReplacePattern(vector& words, string pattern) { + vector ans = {}; + // O(n * k) k is avg word size + for (auto word: words) { + if (matches(word, pattern)) ans.push_back(word); + } + + return ans; + } +}; + +/* abb xyy yxx + +// abbccc +// matches - xyyzzz yzzxxx +// does not match - xyyxxx + +abbccc yzzxxx +abbccc xyyxxx + +if a is mapped to y, then - + - a shall never be mapped to anything else + - no other char shall be mapped to y + +math background - +1:1 mapping +*/ \ No newline at end of file diff --git a/LeetCode/929.unique-email-address.cpp b/LeetCode/929.unique-email-address.cpp new file mode 100644 index 0000000..64aa042 --- /dev/null +++ b/LeetCode/929.unique-email-address.cpp @@ -0,0 +1,32 @@ +class Solution { + string get_normalized(string email) { + int i; + string local_name = ""; + bool ignore_chars = false; + for(i = 0; i < email.size(); i++) { + char c = email[i]; + if (c == '@') { + break; + } + + if (c == '.' || ignore_chars) continue; + if (c == '+') { + ignore_chars = true; + continue; + } + + local_name += c; + } + string domain = email.substr(i); + return local_name + domain; + } +public: + int numUniqueEmails(vector& emails) { + set email_set; + for(string email: emails) { + email_set.insert(get_normalized(email)); + } + + return email_set.size(); + } +}; \ No newline at end of file diff --git a/LeetCode/933.number-of-recent-calls.cpp b/LeetCode/933.number-of-recent-calls.cpp new file mode 100644 index 0000000..20c3f03 --- /dev/null +++ b/LeetCode/933.number-of-recent-calls.cpp @@ -0,0 +1,21 @@ +#include + +class RecentCounter { + deque req; +public: + RecentCounter() { + req = {}; + } + + int ping(int t) { + req.push_back(t); + while(req.front() < t-3000) req.pop_front(); + return req.size(); + } +}; + +/** + * Your RecentCounter object will be instantiated and called as such: + * RecentCounter* obj = new RecentCounter(); + * int param_1 = obj->ping(t); + */ diff --git a/LeetCode/997.find-the-town-judge.cpp b/LeetCode/997.find-the-town-judge.cpp new file mode 100644 index 0000000..a6e9c8c --- /dev/null +++ b/LeetCode/997.find-the-town-judge.cpp @@ -0,0 +1,26 @@ +class Solution { +public: + int findJudge(int n, vector>& trust) { + vector followers(n+1, 0); // 1 based indexing + vector does_follow(n+1, 0); + + map followers, does_follow; // O(logN) + + for(auto edge: trust) { + int u = edge[0], v = edge[1]; + // person u trusts v + followers[v]++; // O(1) v/s in maps O(logN) --> O(1) + does_follow[u] = 1; + } + + vector final_candidates = {}; + for(int i = 1; i <= n; i++) { + if(followers[i] == n-1 && does_follow[i] == 0) { + final_candidates.push_back(i); + } + } + + if(final_candidates.size() != 1) return -1; + return final_candidates[0]; + } +}; diff --git a/Library/Miscellanious/template-short.cpp b/Library/Miscellanious/template-short.cpp new file mode 100644 index 0000000..aa4571c --- /dev/null +++ b/Library/Miscellanious/template-short.cpp @@ -0,0 +1,40 @@ +#include +using namespace std; +#define gc getchar_unlocked +#define fo(i,n) for(i=0;in;k g[N]; +int a[N]; + +void solve() { + +} + +int main() { + ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0); + int t = 1; + cin >> t; + while(t--) { + solve(); + } + return 0; +} + +int mpow(int base, int exp) { + base %= MOD; + int result = 1; + while (exp > 0) { + if (exp & 1) result = ((ll)result * base) % MOD; + base = ((ll)base * base) % MOD; + exp >>= 1; + } + return result; +} \ No newline at end of file diff --git a/Library/Tree/trie.cpp b/Library/Tree/trie.cpp new file mode 100644 index 0000000..ba7d013 --- /dev/null +++ b/Library/Tree/trie.cpp @@ -0,0 +1,160 @@ +#include +#include +#include +#include +#include +using namespace std; + +class Trie { + map m_keys = {}; // what are the next avail chars in trie node + int m_traversed = 0; // how many words in trie are proper prefix + bool m_isLeaf = 0; // is this trie node a leaf node i.e a word ends here + int m_depth = 0; // depth of trie node + +public: + Trie() = default; + Trie(int depth): m_depth(depth) {} + int getDepth() { return m_depth; } + bool isKeyPresent(const char &c) { return m_keys.find(c) != m_keys.end(); } + bool isLeaf() { return m_isLeaf; } + void setLeaf() { m_isLeaf = 1; } + void add(const string &word); + int matchLength(const string &prefix); // returns the length of max prefix that exists in trie + vector getAllWords(); + vector autoComplete(const string &prefix); + bool isPresent(const string &word); + void addKey(const char &c); + Trie *to(const char &c); +}; + +template +void assertVectors(const vector& lhs, const vector& rhs) { + // for(auto e: lhs) + // cout << e << " "; + // cout << endl; + // for(auto e: rhs) + // cout << e << " "; + // cout << endl; + assert(lhs.size() == rhs.size()); + for (int i = 0; i < lhs.size(); i++) + { + assert(lhs[i] == rhs[i]); + } +} + +int main() { + + Trie t; + + vector words = {"Rachit", "Ramesh", "Ankit", "Ankita", "Rachit1"}; + sort(words.begin(), words.end()); + for (auto w : words) + { + t.add(w); + } + + assertVectors(t.autoComplete(""), words); + assertVectors(t.autoComplete("Ra"), {"Rachit", "Rachit1", "Ramesh"}); + assertVectors(t.autoComplete("Rachit"), {"Rachit", "Rachit1"}); + assertVectors(t.autoComplete("Rachit1"), {"Rachit1"}); + assertVectors(t.autoComplete("Rachit12"), {}); + + assert(t.isPresent("")); + assert(!t.isPresent("Racht")); + assert(t.isPresent("Rachit")); + assert(t.isPresent("Rachit1")); + assert(!t.isPresent("Rachit12")); + + assert(t.matchLength("Ract") == 3); + assert(t.matchLength("") == 0); + + return 0; +} + +// add the given char to current Trie node +void Trie::addKey(const char& c) { + if(!isKeyPresent(c)) { + m_keys[c] = new Trie(m_depth + 1); + } + m_traversed++; +} + +Trie* Trie::to(const char& c) { + if(!isKeyPresent(c)) { + return NULL; + } + return m_keys[c]; +} + +// add the word to trie, duplicates are ignored +void Trie::add(const string &word) { + Trie *cur = this; + for (char c: word) + { + cur->addKey(c); + cur = cur->to(c); + } + cur->setLeaf(); +} + +// returns the length of max prefix that exists in trie +int Trie::matchLength(const string &prefix) { + Trie *cur = this; + int match = 0; + for (char c: prefix) { + if (cur->isKeyPresent(c)) { + match++; + cur = cur->to(c); + } + else { + return match; + } + } + return match; +} + +vector Trie::getAllWords() { + vector ans = {}; + for (auto it: m_keys) { + char c = it.first; + Trie *t = it.second; + if (t->isLeaf()) { + ans.push_back(string("") + c); + } + for (auto word: t->getAllWords()) { + ans.push_back(c + word); + } + } + + return ans; +} + +vector Trie::autoComplete(const string &prefix) { + if (!isPresent(prefix)) { + return {}; + } + vector ans = {}; + + Trie *cur = this; + for (char c: prefix) { + if (cur->isKeyPresent(c)) { + cur = cur->to(c); + } + else { + break; + } + } + + if (cur->isLeaf()) { + ans.push_back(prefix); + } + + for (auto restWord: cur->getAllWords()) { + ans.push_back(prefix + restWord); + } + return ans; +} + +bool Trie::isPresent(const string &word) { + return matchLength(word) == word.size(); +} diff --git a/Library/Utils/bits/stdc++.h b/Library/Utils/bits/stdc++.h new file mode 100644 index 0000000..4886b92 --- /dev/null +++ b/Library/Utils/bits/stdc++.h @@ -0,0 +1,117 @@ +// C++ includes used for precompiling -*- C++ -*- + +// Copyright (C) 2003-2015 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/** @file stdc++.h + * This is an implementation file for a precompiled header. + */ + +// 17.4.1.2 Headers + +// C +#ifndef _GLIBCXX_NO_ASSERT +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if __cplusplus >= 201103L +#include +#include +#include +// #include +#include +#include +#include +#include +#include +#endif + +// C++ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if __cplusplus >= 201103L +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif \ No newline at end of file diff --git a/Library/Utils/codeforces.sh b/Library/Utils/codeforces.sh new file mode 100644 index 0000000..444da0b --- /dev/null +++ b/Library/Utils/codeforces.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +# Get the root directory of the Git repository +GIT_ROOT=$(git rev-parse --show-toplevel) + +function enter() { + mkdir -p $GIT_ROOT/CodeforcesContestRunner; + cd $GIT_ROOT/CodeforcesContestRunner; + cp $GIT_ROOT/Library/Miscellanious/template2024.cpp a.cpp + cp $GIT_ROOT/Library/Miscellanious/template2024.cpp b.cpp + cp $GIT_ROOT/Library/Miscellanious/template2024.cpp c.cpp + cp $GIT_ROOT/Library/Miscellanious/template2024.cpp d.cpp + cp $GIT_ROOT/Library/Miscellanious/template2024.cpp e.cpp + echo '' > in.txt +} + +function build() { + problem=$1 + g++ -std=c++20 $problem.cpp -o run_$problem -isystem $GIT_ROOT/Library/Utils +} + +function run() { + problem=$1 + ./run_$problem +} + +function runtxt() { + problem=$1 + ./run_$problem < in.txt +} \ No newline at end of file diff --git a/Library/Utils/logger.h b/Library/Utils/logger.h new file mode 100644 index 0000000..593d3a7 --- /dev/null +++ b/Library/Utils/logger.h @@ -0,0 +1,108 @@ +#include +// #define cerr cout +namespace __DEBUG_UTIL__ +{ + using namespace std; + template + concept is_iterable = requires(T &&x) { begin(x); } && + !is_same_v, string>; + void print(const char *x) { cerr << x; } + void print(char x) { cerr << "\'" << x << "\'"; } + void print(bool x) { cerr << (x ? "T" : "F"); } + void print(string x) { cerr << "\"" << x << "\""; } + void print(vector &v) + { /* Overloaded this because stl optimizes vector by using + _Bit_reference instead of bool to conserve space. */ + int f = 0; + cerr << '{'; + for (auto &&i : v) + cerr << (f++ ? "," : "") << (i ? "T" : "F"); + cerr << "}"; + } + template + void print(T &&x) + { + if constexpr (is_iterable) + if (size(x) && is_iterable) + { /* Iterable inside Iterable */ + int f = 0; + cerr << "\n~~~~~\n"; + for (auto &&i : x) + { + cerr << setw(2) << left << f++, print(i), cerr << "\n"; + } + cerr << "~~~~~\n"; + } + else + { /* Normal Iterable */ + int f = 0; + cerr << "{"; + for (auto &&i : x) + cerr << (f++ ? "," : ""), print(i); + cerr << "}"; + } + else if constexpr (requires { x.pop(); }) /* Stacks, Priority Queues, Queues */ + { + auto temp = x; + int f = 0; + cerr << "{"; + if constexpr (requires { x.top(); }) + while (!temp.empty()) + cerr << (f++ ? "," : ""), print(temp.top()), temp.pop(); + else + while (!temp.empty()) + cerr << (f++ ? "," : ""), print(temp.front()), temp.pop(); + cerr << "}"; + } + else if constexpr (requires { x.first; x.second; }) /* Pair */ + { + cerr << '(', print(x.first), cerr << ',', print(x.second), cerr << ')'; + } + else if constexpr (requires { get<0>(x); }) /* Tuple */ + { + int f = 0; + cerr << '(', apply([&f](auto... args) + { ((cerr << (f++ ? "," : ""), print(args)), ...); }, + x); + cerr << ')'; + } + else + cerr << x; + } + template + void printer(const char *names, T &&head, V &&...tail) + { + int i = 0; + for (size_t bracket = 0; names[i] != '\0' and (names[i] != ',' or bracket != 0); i++) + if (names[i] == '(' or names[i] == '<' or names[i] == '{') + bracket++; + else if (names[i] == ')' or names[i] == '>' or names[i] == '}') + bracket--; + cerr.write(names, i) << " = "; + print(head); + if constexpr (sizeof...(tail)) + cerr << " ||", printer(names + i + 1, tail...); + else + cerr << "]\n"; + } + template + void printerArr(const char *names, T arr[], size_t N, V... tail) + { + size_t i = 0; + for (; names[i] and names[i] != ','; i++) + cerr << names[i]; + for (i++; names[i] and names[i] != ','; i++) + ; + cerr << " = {"; + for (size_t ind = 0; ind < N; ind++) + cerr << (ind ? "," : ""), print(arr[ind]); + cerr << "}"; + if constexpr (sizeof...(tail)) + cerr << " ||", printerArr(names + i + 1, tail...); + else + cerr << "]\n"; + } + +} +#define deb(...) std::cerr << __LINE__ << ": [", __DEBUG_UTIL__::printer(#__VA_ARGS__, __VA_ARGS__) +#define debArr(...) std::cerr << __LINE__ << ": [", __DEBUG_UTIL__::printerArr(#__VA_ARGS__, __VA_ARGS__) \ No newline at end of file