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 diff --git a/LeetCode/Algorithms/Hard/MaximumSumOf3NonOverlappingSubarrays.cpp b/LeetCode/Algorithms/Hard/MaximumSumOf3NonOverlappingSubarrays.cpp new file mode 100644 index 0000000..09dcad5 --- /dev/null +++ b/LeetCode/Algorithms/Hard/MaximumSumOf3NonOverlappingSubarrays.cpp @@ -0,0 +1,100 @@ +class Solution { +public: + vector prefix_sum; + int max_sum; + int mem[20001][3]; // [pos][count] + + int findMaxSum(vector &nums, int pos, int count, int &k) { + if(count == 3) return 0; // done case + if(pos > nums.size() - k) return 0; // not enough item case + if(mem[pos][count] != -1) return mem[pos][count]; // Repeating sub-problem + + // Don't start subarray here + int dont_start = findMaxSum(nums, pos + 1, count, k); + + // Start subarray here + int start_here = findMaxSum(nums, pos + k, count + 1, k) + + + prefix_sum[pos + k] - prefix_sum[pos]; + + return mem[pos][count] = max(dont_start, start_here); + } + + void findMaxSumPath(vector &nums, int pos, int count, int &k, vector &path) { + if(count == 3) return; + if(pos > nums.size() - k) return; + + // Don't start subarray here + int dont_start = findMaxSum(nums, pos + 1, count, k); // In O(1) time + + // Start subarray here + int start_here = findMaxSum(nums, pos + k, count + 1, k) // In O(1) time + + prefix_sum[pos + k] - prefix_sum[pos]; + + if(start_here >= dont_start) { + path.push_back(pos); + findMaxSumPath(nums, pos + k, count + 1, k, path); // Include pos + } else { + findMaxSumPath(nums, pos + 1, count, k, path); // Don't include pos + } + } + + vector maxSumOfThreeSubarrays(vector& nums, int k) { + int n = nums.size(); + memset(mem, -1, sizeof(mem)); // + + // Calculate Prefix-Sum + prefix_sum = vector(n + 1, 0); + for(int i=0; i path; + findMaxSumPath(nums, 0, 0, k, path); + + return path; + } +}; + +// Total no. of subproblems = N * 3 = 3N +// Time Complexity - O(N) +// Space Complexity - O(N) + +// Goal: +// 1. Find 3 non-overlapping Subarrays with max sum +// 2. Return list of start indices (lexicographically smallest in case of +// multiple answers) + +// N = 8 +// K = 2 +// No. of K size Subarrays = (N - K + 1) +// SAs = 7 + +// 0, 1, 2, 3, 4, 5, 6, 7 +// Given: [1, 2, 1, 2, 6, 7, 5, 1] +// [0, 1], [3, 4], [5, 6] sum = 23 -- [0, 3, 5] -> this one is lexicographically smaller +// [1, 2], [3, 4], [5, 6] sum = 23 -- [1, 3, 5] + +// result = [0, 3, 5] +// BF -> O(N ** 3) solution, N^2 > 10^8 + +// Recursive Sum, RS(l, r) = Prefix Sum(r) - Prefix Sum(l - 1) + +// Let's find 2 non overlapping Subarrays with maxSum + +// a[] = [2, 3, 1, 5, 2, 7] +// psum[] = [0, 2, 5, 6, 11, 13, 20] + +// 2 * k size = 2 * 2 = 4 + +// Total no. of subproblems = N * 3 = 3N +// Time Complexity - O(N) +// Space Complexity - O(N) + +// Memoization table + +// 1. Count size column +// 2. N size row \ No newline at end of file diff --git a/LeetCode/Algorithms/Hard/MedianOfTwoSortedArrays.cpp b/LeetCode/Algorithms/Hard/MedianOfTwoSortedArrays.cpp new file mode 100644 index 0000000..6af46dc --- /dev/null +++ b/LeetCode/Algorithms/Hard/MedianOfTwoSortedArrays.cpp @@ -0,0 +1,44 @@ +class Solution { + public: + double findMedianSortedArrays(vector& nums1, vector& nums2) { + vector A = nums1, B = nums2; + + int total = nums1.size() + nums2.size(); + int half = total / 2; + + if(B.size() < A.size()) { + swap(A, B); + } + + // log(min(n, m)) + int l = 0, r = A.size() - 1; + while(true) { + int i = (l + r) / 2; // for A + int j = half - i - 2; // B + + // A -> Aright + // B -> Bleft + + // A -> Aleft + // B -> Bright + int Aleft = (i >= 0) ? A[i] : INT_MIN; + int Aright = (i + 1) < A.size() ? A[i + 1] : INT_MAX; + int Bleft = (j >= 0) ? B[j] : INT_MIN; + int Bright = (j + 1) < B.size() ? B[j + 1] : INT_MAX; + + // parition is correct + if(Aleft <= Bright && Bleft <= Aright) { + // if odd + if(total % 2) { + return min(Aright, Bright); + } + // even + return (max(Aleft, Bleft) + min(Bright, Aright)) / 2; + } else if(Aleft > Bright) + r = i - 1; + } else if(Bleft > Bright) { + l = i + 1; + } + } + } +}; \ No newline at end of file diff --git a/LeetCode/Algorithms/Hard/MinimumIntervalToIncludeEachQuery.cpp b/LeetCode/Algorithms/Hard/MinimumIntervalToIncludeEachQuery.cpp new file mode 100644 index 0000000..6105ccf --- /dev/null +++ b/LeetCode/Algorithms/Hard/MinimumIntervalToIncludeEachQuery.cpp @@ -0,0 +1,59 @@ +#define pii pair +class Solution { + public: + struct myComp { + bool operator() (pair &a, pair &b) { + if(a.first == b.first) { + return a.second < b.second; + } + return a.first > b.first; + } + }; + + vector minInterval(vector>& intervals, vector& queries) { + sort(intervals.begin(), intervals.end(), [](vector &a, vector &b) { + return a[0] < b[0]; + }); + + vector sorted_query = queries; + sort(sorted_query.begin(), sorted_query.end()); + + // priority_queue, greater> pq; + priority_queue, myComp> pq; + + int i = 0; + unordered_map m; + for(auto &q: sorted_query) { + // adding all the intervals + while(i < intervals.size() && intervals[i][0] <= q) { + auto &temp = intervals[i]; + int l = temp[0]; + int r = temp[1]; + pq.push({(r - l + 1), r}); + i++; + } + + // removing invalid intervals from + // priority queue + while(!pq.empty() && pq.top().second < q) { + pq.pop(); + } + + if(!pq.empty()) { + m[q] = pq.top().first; + } else { + m[q] = -1; + } + } + + vector result; + for(auto &q: queries) { + result.push_back(m[q]); + } + return result; + } +}; + +// Time Complexity - O(nlogn + qlogq), +// q is length of queries +// n is the lenght of intervals \ No newline at end of file diff --git a/LeetCode/Algorithms/Hard/MinimumWindowSubstring.cpp b/LeetCode/Algorithms/Hard/MinimumWindowSubstring.cpp new file mode 100644 index 0000000..91599cb --- /dev/null +++ b/LeetCode/Algorithms/Hard/MinimumWindowSubstring.cpp @@ -0,0 +1,46 @@ +class Solution { + public: + string minWindow(string s, string t) { + if(t == "") return ""; + + unordered_map countT, window; + + for(auto c: t) { + countT[c]++; + } + + int have = 0, need = countT.size(); + int l = 0; + pair result; + int resLen = INT_MAX; + for(int r=0; rnext; + curr->next = prev; + prev = curr; + curr = futureNode; + } + return prev; + } + ListNode* reverseKGroup(ListNode* head, int k) { + ListNode *temp = head; + ListNode *prevLast = NULL; + + while(temp != NULL) { + ListNode *kthNode = getKthNode(temp, k); + if(kthNode == NULL) { // only when List is larger than K + if(prevLast != NULL) { + prevLast->next = temp; + } + break; + } + + ListNode *nextNode = kthNode->next; + kthNode->next = NULL; + reverseLL(temp); + + if(temp == head) { + head = kthNode; + } else { + prevLast->next = kthNode; + } + + prevLast = temp; + temp = nextNode; + } + return head; + } + + ListNode *getKthNode(ListNode *temp, int k) { + k--; + while(temp != NULL && k > 0) { + temp = temp->next; + k--; + } + return temp; + } +}; + +/* +Time Complexity - O(N) +Space Complexity - O(1) +*/ \ No newline at end of file diff --git a/LeetCode/Algorithms/Hard/TrappingRainWater2.cpp b/LeetCode/Algorithms/Hard/TrappingRainWater2.cpp new file mode 100644 index 0000000..f3e8db0 --- /dev/null +++ b/LeetCode/Algorithms/Hard/TrappingRainWater2.cpp @@ -0,0 +1,62 @@ +class Solution { +public: + #define pi pair> + + bool isValid(int &x, int &y, int &m, int &n) { + return (x >= 0 && x < m && y >= 0 && y < n); + } + int trapRainWater(vector>& heightMap) { + int m = heightMap.size(); + int n = heightMap[0].size(); + + if(m < 3 && n < 3) { + return 0; + } + + // Step-1: Push all boundary elements as START points + priority_queue, greater> minheap; + vector> visited(m, vector(n, false)); + + for(int i=0; i dir = {-1, 0, 1, 0, -1}; // URDL 4-dir calls + while(!minheap.empty()) { + pi curr = minheap.top(); + minheap.pp(); + + int height = curr.first; + int x = curr.second.first; + int y = curr.second.second; + level = max(level, height); + + // 4-directional traversal + for(int i=0; i<4; i++) { + int newX = x + dir[i]; + int newY = x + dir[i + 1]; + if(isValid(newX, newY, m, n) && !visited[newX][newY]) { + visited[newX][newY] = true; + minheap.push(make_pair(heightMap[newX][newY], make_pair(newX, newY))); + if(heightMap[newX][newY] < level) { + trapped_water += level - heightMap[newX][newY]; + } + } + } + } + return trapped_water; + } +}; + +// Time Complexity - O(M * N * log(M * N)), log(M * N) is the heap arrangement, +// M * N is Total Cells +// Space Complexity - O(M * N), visited array min heap + diff --git a/LeetCode/Algorithms/Medium/ConstructStringWithRepeatLimit.cpp b/LeetCode/Algorithms/Medium/ConstructStringWithRepeatLimit.cpp new file mode 100644 index 0000000..fdff5d0 --- /dev/null +++ b/LeetCode/Algorithms/Medium/ConstructStringWithRepeatLimit.cpp @@ -0,0 +1,80 @@ +class Solution { +public: + #define pii pair + string repeatLimitedString(string s, int repeatLimit) { + priority_queue pq; + + vector freq(26, 0); + for(int i=0; i 0) { + pq.push({i, freq[i]}); + } + } + + string result; + while(!pq.empty()) { + pii curr = pq.top(); + pq.pop(); + + char curr_char = 'a' + curr.first; + int count = min(repeatLimit, curr.second); + result.append(count, curr_char); + curr.second -= count; + + if(curr.second > 0) { + if(pq.empty()) { + break; + } + pii next = pq.top(); + pq.pop(); + + char next_char = 'a' + next.first; + + result.push_back(next_char); + next.second--; + if(next.second > 0) { + pq.push(next); + } + pq.push(curr); + } + } + return result; + } +}; + +// Time Complexity - O(N * log(26)) ~ O(n) +// Space Complexity - O(26) ~ O(1), since we're using a max heap of size 26 +// from a to z + +// Goal +// Build lexicographical largest string where no same chars occurs +// more than the repeat limit times + +// s1 = abac +// s2 = abba +// x +// s2 > s1 (b > a) + +// s1 = abb +// s2 = ac +// x +// s2 > s1 (c > b) + +// s1 = abb +// s2 = ab +// s1 > s2 (since size of s1 > s2) + +// build stirng using map +// weightage + +// Greedily place highest valued item to highest weight position +// (2 3 4 7) -> 7 4 3 2 + +// maxheap +// s = aaaabbcccc +// repeat limit = 3 +// ans = cccbcbaaa (a - z (97 - 122)) diff --git a/LeetCode/Algorithms/Medium/ConstructTheLexicographicallyLargestValidSequence.cpp b/LeetCode/Algorithms/Medium/ConstructTheLexicographicallyLargestValidSequence.cpp new file mode 100644 index 0000000..350afec --- /dev/null +++ b/LeetCode/Algorithms/Medium/ConstructTheLexicographicallyLargestValidSequence.cpp @@ -0,0 +1,51 @@ +class Solution { +public: + bool findLargestArray(vector &result, vector &used, int pos, int n) { + if(pos == 2 * n - 1) { + return true; + } + + if(result[pos] != 0) { // already filled + return f(result, used, pos + 1, n); + } + + // Try assigning all unused values + for(int i=n; i>=1; i--) { + if(used[i] == true) continue; + + used[i] = true; + result[pos] = i; + if(i == 1 && findLargestArray(result, used, pos + 1, n)) { + return true; + } + if(i > 1 && (pos + i) < (2 * n - 1) && result[pos + i] == 0) { + result[pos + i] = i; + if(findLargestArray(result, used, pos + 1, n)) { + return true; + } + + result[pos + i] = 0; + } + used[i] = false; + result[pos] = 0; + } + return false; + } + + vector constructDistancedSequence(int n) { + vector used(n + 1, false); + vector result(2 * n - 1, 0); + + findLargestArray(used, result, 0, n); + return result; + } +}; + + +// Time Complexity - O(N!) +// Space Complexity - O(N), depth of recursion + +// Runtime << N! because: +// 1. Equi-distant placement of Nos reduces a lot of arrangements of N! +// 2. Early stopping by greedy recursion + diff --git a/LeetCode/Algorithms/Medium/ContinuousSubarrays.cpp b/LeetCode/Algorithms/Medium/ContinuousSubarrays.cpp new file mode 100644 index 0000000..c4df457 --- /dev/null +++ b/LeetCode/Algorithms/Medium/ContinuousSubarrays.cpp @@ -0,0 +1,77 @@ +class Solution { +public: + #define ll long long + + long long continuousSubarrays(vector& nums) { + int n = nums.size(); + int range_min = INT_MAX; + int range_max = INT_MIN; + int left = 0; + int right; + + ll count = 0; + ll win_size; + + for(right = 0; right < n; right++) { + range_min = min(range_min, nums[right]); + range_max = max(range_max, nums[right]); + + if((range_max - range_min) > 2) { + win_size = right - left; + count += ((win_size) * (win_size + 1)) / 2; + + left = right; + // Expand ranges to current value for right + range_min = nums[right]; + range_max = nums[right]; + + while(abs(nums[right] - nums[left - 1]) <= 2) { + left--; + range_min = min(range_min, nums[left]); + range_max = max(range_max, nums[left]); + } + // Substract overcounted subarrays + if(left < right) { + win_size = (right - left); + count -= (win_size * (win_size + 1)) / 2; + } + } + } + // Add subarrays from last window + win_size = (right - left); + count += ((win_size) * (win_size + 1)) / 2; + return count; + } +}; + +// Time Complexity - O(N) +// Space Complexity - O(1) + +// Constraint: In a Subarray: abs(nums[i] - nums[j]) <= 2 + +// Goal: Count No. of such subarrays + +// Generate all possible Subarrays +// For each Subarray, (max - min) <= 2 +// count++; + +// Counting Subarrays +// No of SAs with size n = (n * (n + 1)) / 2 + +// [5, 3, 4] +// no. of subarrays = (3 * 4) / 2 = 6 + +// [5], [5, 3], [5, 3, 4], [3], [3, 4], [4] + +// range_max = -inf , check |max - min| <= 2 +// rnage_min = inf +// win_size = R - L => total ===> count = (total) * (total + 1) / 2 +// count = 0 + +// L -> x you won't know when to STOP + +// L = R +// then <------ L when the 1st out of bound element comes STOP x + +// Sliding Window (2 Pointer) + diff --git a/LeetCode/Algorithms/Medium/CountTheNumberOfGoodSubarrays.cpp b/LeetCode/Algorithms/Medium/CountTheNumberOfGoodSubarrays.cpp new file mode 100644 index 0000000..b8c13d3 --- /dev/null +++ b/LeetCode/Algorithms/Medium/CountTheNumberOfGoodSubarrays.cpp @@ -0,0 +1,78 @@ +class Solution { + using ll = long long; + public: + long long countGood(vector& nums, int k) { + ll n = nums.size(); + ll left = 0, right = 0; + ll good_subarrays = 0; + unordered_map freq; + ll equal_pairs = 0; + + while(left < n) { + while(right < n and equal_pairs < k) { + freq[nums[right]]++; + if(freq[nums[right]] >= 2) { + equal_pairs += freq[nums[right]] - 1; + } + right++; + } + + if(equal_pairs >= k) { + good_subarrays += n - right + 1; + } + + // remove left item + freq[nums[left]]--; + if(freq[nums[left]] > 0) { + equal_pairs -= freq[nums[left]]; + } + left++; + } + return good_subarrays; + } +}; + +/* +Time Complexity - O(N) +Space Complexity - O(N) + + + 0 1 2 3 4 5 6 7 +[1 5 2 5 3 2 5 6] , K = 2 + +[0, 5] = valid + +n = 8 +n - i = 8 - 5 = 3 + 3 = 6 + +All Subarrays starting from 0 & ending at idx >= 5 will alwys be valid + +count of equal pairs >= k + +maybe starting at idx > 0 and ending at 5 would also be valid! + +Try for increasing left indices unless the Subarray has count of equals pairs < k +=> then extend the right end of subarray + +Two pointer and sliding window + +-> Count Equal pairs + + 0 1 2 3 4 5 6 +[1 2 1 1 2 1 2] + +f(1) = 4 => 3 + 2 + 1 = 3 * 4 / 2 = 6 + +Element | Frequency + 1 4 + 2 3 + +Equal(1, 1) pairs = 4 * 3 / 2 => (n * (n - 1)) / 2 + = 6 + +Equal (2, 2) pairs = 3 * 2 / 2 = 3 + +Total equal pairs = 6 + 3 = 9 + + +*/ \ No newline at end of file