diff --git a/LeetCode/Algorithms/CountSubsetsWithSumK.cpp b/LeetCode/Algorithms/CountSubsetsWithSumK.cpp new file mode 100644 index 0000000..8e43621 --- /dev/null +++ b/LeetCode/Algorithms/CountSubsetsWithSumK.cpp @@ -0,0 +1,32 @@ +int mod = (int)(1e9 + 7); +int f(vector &arr, int ind, int sum, vector> &dp) { + // if(sum == 0) return 1; + if(ind == 0) { + if(sum == 0 && arr[0] == 0) return 2; // 0 0 1 2 3, target = 5 - to handle case where multiple 0's + if(sum == 0) return 1; // + return arr[0] == sum; + // if(sum == 0 || sum == arr[0]) return 1; + // return 0; + } + if(dp[ind][sum] != -1) return dp[ind][sum]; + // not take + int notTake = f(arr, ind - 1, sum, dp); + + // take + int take = 0; + if(sum >= arr[ind]) { + take = f(arr, ind -1, sum - arr[ind], dp); + } + + return dp[ind][sum] = (take + notTake) % mod; +} + +int findWays(vector& arr, int k) +{ + // Write your code here. + int n = arr.size(); + vector> dp(n, vector(k + 1, -1)); + return f(arr, n-1, k, dp); +} + + diff --git a/LeetCode/Algorithms/DisjoinSet.cpp b/LeetCode/Algorithms/DisjoinSet.cpp new file mode 100644 index 0000000..e55db19 --- /dev/null +++ b/LeetCode/Algorithms/DisjoinSet.cpp @@ -0,0 +1,78 @@ +#include +using namespace std; +class DisjoinSet { + vector rank, parent, size; + +public: + DisjoinSet(int n) { + rank.resize(n + 1, 0); + size.resize(n + 1, 0); + parent.resize(n + 1); + for(int i=0; i<=n; i++) { + parent[i] = i; + size[i] = 1; + } + } + + int findUPar(int node) { + if(node == parent[node]) { + return node; + } + return parent[node] = findUPar(parent[node]); + } + + void UnionByRank(int u, int v) { + int ulp_u = findUPar(u); + int ulp_v = findUPar(v); + + if(ulp_u == ulp_v) { + return; + } else if(rank[ulp_v] > rank[ulp_u]) { + parent[ulp_u] = ulp_v; + } else if(rank[ulp_u] > rank[ulp_v]) { + parent[ulp_v] = ulp_u; + } else if(rank[ulp_u] == rank[ulp_v]) { + parent[ulp_v] = ulp_u; + rank[ulp_v]++; + } + } + + void UnionBySize(int u, int v) { + int ulp_u = parent[u]; + int ulp_v = parent[v]; + + if(ulp_u == ulp_v) return; + if(size[ulp_u] > size[ulp_v]) { + size[ulp_u] += size[ulp_v]; + parent[ulp_v] = ulp_u; + } else { + size[ulp_v] += size[ulp_u]; + parent[ulp_u] = ulp_v; + } + } +}; + +int main() { + DisjoinSet ds(7); + ds.UnionByRank(1, 2); + ds.UnionByRank(2, 3); + ds.UnionByRank(4, 5); + ds.UnionByRank(6, 7); + ds.UnionByRank(5, 6); + // ds.UnionByRank(1, 2); + + // if 3 and 7 same or not + if(ds.findUPar(3) == ds.findUPar(7)) { + cout<<"Same"<start = start; + * this->end = end; + * } + * } + */ + +class Solution { +public: + // struct myComp { + // bool operator() (Interval &a, Interval &b) { + // return a.start < b.start; + // } + // }; + + static bool myComp(const Interval &a, const Interval &b) { + return a.start < b.start; + } + + bool canAttendMeetings(vector& intervals) { + if(intervals.empty()) return true; + sort(intervals.begin(), intervals.end(), myComp); + + // sort(intervals.begin(), intervals.end(), myComp()); + + // sort(intervals.begin(), intervals.end(), [](Interval &a, Interval &b) { + // return a.start < b.start; + // }); + + int prevEnd = intervals[0].end; + + for(int i=1; i& nums, long long k) { + ll left = 0, right = 0; // window is [left, right) + ll sum = 0; // sum of nums[left ... right -1] + ll count = 0; + + ll n = nums.size(); + + while(left < n) { + // find larget valid window + while(right < n && (sum + nums[right] * (right - left + 1) < k)) { + sum += nums[right]; + right++; + } + + // All subarrays starting at 'left' and ending before 'right' are valid + count += right - left; + + // Slide the window forward by removing nums[left] + // If we couldn't even include nums[left], move both pointer past it + if(left == right) { + right++; + } else { + sum -= nums[left]; + } + + left++; + } + + return count; + } +}; + +/* + +Time Complexity - O(N) +Space Complexity - O(1) + +Counting Logic + 0 1 2 3 4 5 +a[]: [2, 1, 1, 3, 4, 1], k = 15 + | | + start end + +1. Increase end till sum * len < k +2. Count = end - start +3. Increase start pointer and again when sum * len >= k, + calculate count and increment start++ pointer + +[start, End) => largest subarray starting at '0' which has (sum * size) < k + +start, end - 1 ie 4 * 3 < 15 + +Count of such Subarrays start at '0' = 3 + +in general [start, start], [start, start+ 1], ... [start, end-1] + +count = end - start + +// Two Pointer + Sliding Window + + + +*/ \ No newline at end of file diff --git a/LeetCode/Algorithms/Hard/FindMinimumDiameterAfterMergingTwoTrees.cpp b/LeetCode/Algorithms/Hard/FindMinimumDiameterAfterMergingTwoTrees.cpp new file mode 100644 index 0000000..35504e9 --- /dev/null +++ b/LeetCode/Algorithms/Hard/FindMinimumDiameterAfterMergingTwoTrees.cpp @@ -0,0 +1,111 @@ +class Solution { +public: + int diameter(unordered_map>& adj, int n) { + // pick any node and find the farthest from that node + vector visited(n, false); + queue q; + q.push(0); + visited[0] = true; + int last; + while(!q.empty()) { + int size = q.size(); + for(int i=0; i vis(n, false); + vis[last] = true; + while(!q.empty()) { + int size = q.size(); + for(int i=0; i>& edges) { + if(edges.size() == 0) { + return 0; + } + + unordered_map> adj; + unordered_set nodes; + + for(auto &edge: edges) { + cout<>& edges1, vector>& edges2) { + int dia1 = findDiameter(edges1); + int dia2 = findDiameter(edges2); + + int radius1 = (dia1 + 1) / 2; + int radius2 = (dia2 + 1) / 2; + int sum = 1 + radius1 + radius2; + + return max(sum, max(dia1, dia2)); + } +}; + +// Time Complexity - O(N + M) +// Space Complexity - O(N + M) + +// Follow-up +// 1. Prove the greedy algo. +// 2. Find al diameters of a tree + +// How to find optimal path? + +// Note: It is always optimal to join at midpoint of diameter + +// total height = h1 / 2 + bridge (1) + h2 / 2 + +// Cases + +// Even-Even ==> ans = 1 + dia1 / 2 + dia2 / 2 +// Odd-Even ==> ans = 1 + (dia1 + 1) / 2 + dia2 / 2 +// Odd-Odd ==> ans = 1 + (dia1 + 1) / 2 + (dia2 + 1) / 2 + +// How to find diameter of undirected tree? +// Greedy Algorithm +// 1. Choose any node (a) +// 2. Find farthest node from a (b) --> BFS(levelorder) +// 3. Find farthest node from b and count no. of hops / levels +// diameter = no. of hops + +// Case 1: Your chosen node is already on diameter + +// Joining may not always contain diameter + +// max diameter = max{dia1, dia2, 1 + (dia1 + 1) / 2 + (dia2 + 1) / 2} + + diff --git a/LeetCode/Algorithms/Hard/LargestRectangleInHistogram.cpp b/LeetCode/Algorithms/Hard/LargestRectangleInHistogram.cpp new file mode 100644 index 0000000..7149fcf --- /dev/null +++ b/LeetCode/Algorithms/Hard/LargestRectangleInHistogram.cpp @@ -0,0 +1,42 @@ +class Solution { +public: + int largestRectangleArea(vector& heights) { + int maxArea = 0; + stack> stk; // (index, height) + int n = heights.size(); + for(int i=0; i heights[i]) { + auto temp = stk.top(); + stk.pop(); + + int index = temp.first; + int height = temp.second; + maxArea = max(maxArea, height * (i - index)); + start = index; + } + + stk.push({start, heights[i]}); + } + + // calculate the area of the remaining elements + // in stack, area to be calcualted by condering from + // length of height array + while(!stk.empty()) { + auto temp = stk.top(); + stk.pop(); + + int index = temp.first; + int height = temp.second; + + maxArea = max(maxArea, height * (n - index)); + } + return maxArea; + } +}; + +// Time Complexity - O(N) +// Space Complexity - O(N) \ No newline at end of file diff --git a/LeetCode/Algorithms/Hard/MaximumNumberOfTasksYouCanAssign.cpp b/LeetCode/Algorithms/Hard/MaximumNumberOfTasksYouCanAssign.cpp new file mode 100644 index 0000000..616b7fe --- /dev/null +++ b/LeetCode/Algorithms/Hard/MaximumNumberOfTasksYouCanAssign.cpp @@ -0,0 +1,156 @@ +class Solution { + public: + bool canAssign(int mid, vector &workers, vector &tasks, int pills, int strength) { + // it means that if mid = 2, we'll be taking the last two values in workers and putting them in multiset + multiset usable_workers(workers.end() - mid, workers.end()); + + // iterating from right to left + for(int i=mid-1; i>=0; i--) { + auto curr_workers = --usable_workers.end(); + + if(*curr_workers < tasks[i]) { + if(pills <= 0) return false; + + // Optimal Strategy: Assign weakest worker to get the current task done + auto weakest_worker = usable_workers.lower_bound(tasks[i] - strength); + + if(weakest_worker == usable_workers.end()) { + return false; // no one can be assigned the current job (even using pill) + } + + pills--; + usable_workers.erase(weakest_worker); + } else { + usable_workers.erase(curr_workers); + } + } + return true; + } + + int maxTaskAssign(vector& tasks, vector& workers, int pills, int strength) { + sort(workers.begin(), workers.end()); + sort(tasks.begin(), tasks.end()); + + int low = 0; + int high = min(tasks.size(), workers.size()); + int mid; + + int assigned = 0; + while(low <= high) { + mid = low + (high - low) / 2; + + if(canAssign(mid, workers, tasks, pills, strength)) { + assigned = mid; + low = mid + 1; + } else { + high = mid - 1; + } + } + + return assigned; + } +}; + +/* +Optimal Matchup Strategy + +Strategy - 1: Strong fights the weak + +Strategy - 2: Strong fights strong. (fair) -- choose this one + +Ques: What if you have G > R or G < R + +Note: Sort to search optimal matchups faster + +Goal: Get more wins for green + +Note: +Fights are only 1:1 +A person can only fight once + +1 7 6 +2 6 5 + +Sorting: + +1. Remove the person who is the strongest in the opposite team + + +I. +II. 2, (4, 5, 6) -> (N - M) workers ignore + +Sorted Asc: Strongest worker gets hardest job + 0 1 2 +T[]: [6, 7, 7] , Pill = 1, Strength = 3 +W[]: [2, 5, 6] + +Lower bound binary search: + + 0 1 2 3 4 5 6 7 +[1, 2, 2, 4, 4, 5, 7, 7] + +lb(2) = 1 +lb(6) = 6 + +// set shoudl not be used because the order is not unique + +multiset works well in this scenario since it preserves order +or +ordered_map + +Max tasks to be done <= Max workers + + 0 1 2 3 4 +T[] : [7, 6, 8, 7, 9] => T[]: [6, 7, 7, 8, 9] + <---- | ignore + 0 1 2 0 1 2 +W[] : [6, 2, 5] => W[]: [2, 5, 6] + +Strategy: Choose weakest M tasks + +If N < M then only N workers + + 0 1 +T[]: [6, 7] --> N + + 0 1 2 +W[]: [2, 5, 6] --> M +ignore| + +M > N + +Note: R->L is imp to match strongest W[i] with toughest task + +Max No of Tasks: Similar to Leetcode's First Bad version probelm + +Goal: Find max tasks which can be done +-> find the first bad version + +low = 0 +high = min(N, M) +mid = low + (high - low) / 2 + +if(canAssign(mid)) { + assigned = mid; + love = mid + 1; +} else { + love = mid - 1; +} + +pick strongest worker and weakest task, so that we have change of completing the task + +Time Complexity - + +W = min(N, M) + +logW * W * logW += W(logW)**2 + +Binary Search ---> Loop ---> lower bound on multiset + + +Total time Complexity - W(logW)^2 + NlogN + MlogM, tasks and workers array will also be sorted +Space Complexity - O(W), due to multiset / map being used + +W = min(N, M) +*/ \ No newline at end of file