Repository: nisarg0/Algorithm-Implementation Branch: master Commit: 1214f458b5b6 Files: 67 Total size: 96.9 KB Directory structure: gitextract_8xc2r5t4/ ├── .gitignore ├── Adhoc + Basic/ │ ├── Reservoir_sampling.cpp │ ├── Sieve_of_Eratosthenes.cpp │ ├── Two_Pointer.cpp │ ├── binary_search_I.cpp │ ├── binary_search_II.cpp │ └── binary_search_III.cpp ├── Arrays/ │ ├── MedianOfSortedArrays.cpp │ ├── MedianOfStream.cpp │ ├── MonotonicStack.cpp │ ├── Sliding Window Max.cpp │ ├── TrappingRainwater.cpp │ └── readme.md ├── Bit-mask/ │ └── Bitmask_Basic.cpp ├── DP/ │ ├── LCS.cpp │ ├── LIS.cpp │ ├── LongestPalindromicSubstring.cpp │ ├── LongestPanlidromicSubsequence.cpp │ ├── MatrixChainMulti.cpp │ ├── PalindromicCuts.cpp │ ├── digit_dp.cpp │ └── travelling_salesman_prob.cpp ├── Geometry/ │ └── anglecoverted.cpp ├── Graph/ │ ├── BFS.cpp │ ├── Bellman_ford(Negative_weights).cpp │ ├── Bipartite_Coloring.cpp │ ├── Bipartite_matching.cpp │ ├── DFS.cpp │ ├── FloydWarshall.cpp │ ├── README.md │ ├── cycleDetection.cpp │ ├── dijkstra.cpp │ ├── prims_algo.cpp │ ├── topological_sort.cpp │ └── union_find_algo.cpp ├── Greedy or DP (Problems)/ │ ├── Continuous_subarray_sum.cpp │ ├── Job_scheduling.cpp │ ├── Kadane.cpp │ ├── Queue_Reconstruction.cpp │ ├── jump_problem.cpp │ └── variations.txt ├── Matrix or Backtracking(Problems)/ │ └── Max_Submatrix_with_LT_Ksum.cpp ├── NumberTheory/ │ └── RandomNum.cpp ├── OS Concept based algos/ │ └── LRU-Cache.cpp ├── README.md ├── Range_queries/ │ ├── Mo's_algo.cpp │ ├── Persisitant tree.cpp │ ├── Range_Update(Difference_Array).cpp │ ├── Segment_trees.cpp │ ├── sparce_table.cpp │ ├── sqrt_decomposition.cpp │ └── which_to_use_when.txt ├── Sorting Algorithms/ │ ├── HeapSort.cpp │ ├── Inbuilt_sorting_algos.cpp │ ├── MergeSort.cpp │ ├── O(n^2)_Algos.cpp │ ├── QuickSort.cpp │ ├── RadixSort.cpp │ └── cycleSort.cpp ├── Strings/ │ ├── KMP.cpp │ ├── PatternMatching.cpp │ └── string_input.cpp ├── Trees/ │ ├── Binary_Lifting.cpp │ ├── LCA.cpp │ ├── WordSearch2.cpp │ └── trie.cpp └── codesnippet.cpp ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ .vscode/* ================================================ FILE: Adhoc + Basic/Reservoir_sampling.cpp ================================================ /** * Question: Is there a way to get random number from a stream of integers? * Yes. We create a reserviour of size 1 (single element). * We iterate over the stream and for each element we have a probability of 1/i to replace the element in the reserviour. * This is because the probability of not replacing the element is (i-1)/i and the probability of replacing the element is 1/i. * So the probability of not replacing the element after i iterations is (i-1)/i * (i-2)/i-1 * ... * 1/2 = 1/i. * * Ref: https://www.youtube.com/watch?v=A1iwzSew5QY * Que: https://leetcode.com/problems/linked-list-random-node/ */ #include using namespace std; int findRandom(vector arr) { int reservoir, len = 0; reservoir = arr[0]; len = 1; while (len < arr.size()) { // probability of replacing charachter in reservoir is 1/len // Assuming rand() produces int upto infinity if (rand() % len == 0) { reservoir = arr[len]; } len++; } return reservoir; } // getting random index based on weight in a stream on weights // print randomNum when 0 comes in stream int weightedRandomIndex(const std::vector& weights) { double totalWeight = 0; int selectedIndex = -1; for (int i = 0; i < weights.size(); ++i) { if (weights[i] == 0) cout << selectedIndex; totalWeight += weights[i]; if (((double)rand()) / RAND_MAX * totalWeight < weights[i]) { selectedIndex = i; } } return selectedIndex; } int main() { vector arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; cout << "Radom num from inf list is " << findRandom(arr); } ================================================ FILE: Adhoc + Basic/Sieve_of_Eratosthenes.cpp ================================================ /*Questions solved precomputation -> O(N(lnlnN)) 1. is n a prime -> O(1) 2. factors of some F -> O(ln NF) 3. primes between a range -> O(range) 4. smallest prime greater than k -> O(ln k) */ #include using namespace std; #define LIM 10000 bool isComposite[LIM]; int factor[LIM]; //stores one of the factor of the indx, we can find other factor easily vector primes; //stores list of primes in LIM int main() { int i; //PreComputation isComposite[1]=true; //assume for simplicity as 1 is NOT PRIME. for(int i=2;i>n; cout<>F; while (isComposite[F] and F!=1) { cout<>a>>b; auto itr = upper_bound(primes.begin(),primes.end(),a); for( ; *itr <= b and itr!=primes.end() ; itr++ ) { cout<<*itr<<" "; } //Q4 int k; cin>>k; cout<<"Enter number to get just greater prime:"; cin>>k; itr = upper_bound(primes.begin(),primes.end(),k); if(itr!=primes.end()) cout<<*itr; } ================================================ FILE: Adhoc + Basic/Two_Pointer.cpp ================================================ // Dutch National Flag Problem // Sot 0,1,2 with a single traversal /* * Must satisfy condn * [start,lo] = 0 * [hi+1,end] = 2 * [mid, hi-1] = Don't know */ // Array has 0,1,2 as elements sort the array: void sortColors(vector& arr) { int lo=0,mid=0,hi=arr.size()-1; // while(mid <= hi) { if(arr[mid] == 0) swap(arr[lo++],arr[mid]); else if(arr[mid] == 1) mid++; else // arr[mid] = 2 swap(arr[hi--],arr[mid]); } } ================================================ FILE: Adhoc + Basic/binary_search_I.cpp ================================================ // Question link -> https://community.topcoder.com/stat?c=problem_statement&pm=1901&rd=4650 // Artical link -> https://www.topcoder.com/community/competitive-programming/tutorials/binary-search // Ref link -> https://www.youtube.com/watch?v=GU7DpgHINWQ // Ref link -> https://leetcode.com/discuss/interview-question/1322500/5-variations-of-Binary-search-(A-Self-Note)/?fbclid=IwAR1tgOv9b7dNA9dyqBEHCmNdqkGrBxItE7vqBRVqL0Rk6UE65_fLO8J1JI8 // Here in binary search we basically want o function that return boolean value if it is ans yes or no // And we want the indxe from where true begins or false begins #include using namespace std; int getMostWork_method1(int folders[], int workers,int n) { // Number of workers maximum in a division can be between 1 and 10^6(Can be lower but in general) int lo = 1, hi = 1e5+1; while (lo < hi) { int mid = lo + (hi - lo) / 2; int required = 1, sum = 0; for (int i = 0; i < n; ++i) { if (sum + folders[i] <= mid) // the current worker can handle it sum += folders[i]; else // assign nemidt worker { ++required; sum = folders[i]; } } // | is the indx we want to find // F F F F F F F T T T T T T // if(p(mid)==true) hi = mid if (required <= workers) hi = mid; else lo = mid + 1; } return lo; // lo=hi so doesn't matter } bool ispossible(int folders[],int n, int no, int workers) { int required = 1, sum = 0; for (int i = 0; i < n; ++i) { if (sum + folders[i] <= no) // the current worker can handle it sum += folders[i]; else // assign nemidt worker { ++required; sum = folders[i]; } } if(required <= workers) return true; return false; } int getMostWork_method2(int folders[],int workers, int n) { int hi=1e9,lo=0,mid; bool check_low,check_mid,check_upp; while(lo <= hi) { mid = (lo+hi)/2; check_low=ispossible(folders,n,mid-1,workers); check_mid=ispossible(folders,n,mid,workers); check_upp=ispossible(folders,n,mid+1,workers); if(check_low==0 && check_mid==1) return mid; else if(check_mid==0 && check_upp==1) return mid+1; else if(check_upp==1) hi=mid+1; else if(check_low==0) lo=mid-1; } return 0; } int main() { int arr[15] = { 568, 712, 412, 231, 241, 393, 865, 287, 128, 457, 238, 98, 980, 23, 782 }; int n = sizeof(arr)/sizeof(int); // Divide the work in 4 workers such that the work done per worker is minimum cout << "Minimum possible maximum folders per person " < https://www.youtube.com/watch?v=U66U1-umNbQ&t=1s // Reference --> https://www.youtube.com/watch?v=V343UXw4P3Y // upper bound return first element which is >value. If not, return end(). // lower bound return first element which is ≥value. If not, return end(). /* Elements are : 1 3 5 7 9 ******* lower_bound ********* lower bound of 5 in the set is: 5 lower bound of 1 in the set is: 1 lower bound of 4 in the set is: 5 ****** upper_bound ************ upper bound of 5 in the set is: 7 upper bound of 1 in the set is: 3 upper bound of 4 in the set is: 5 */ #include using namespace std; /* * Intresting observation note worthy : * lo+(hi-lo)/2 = (lo+hi)/2 is skewed to towards lo. (ex. (1+4)/2 = 2.5 but it return 2) * hi = mid can be seen a skewed towards hi so this (lo+hi)/2 works fine with hi = mid * Similarly * lo = mid is skewed towards lo so using (lo+hi)/2 A as mid will result in SEG so instead use * (hi-lo+1)/2 is skewed towards hi ex. 1+(4-1+1)/2 = 3.5 = 3 so we got ceil(2.5) * mid = lo + (hi-lo+1)/2 */ int lower_bound_(vector arr, int target){ int lo = 0; int hi = arr.size()-1; while(lo target) hi = mid-1; // Our index needed may be this index mid or may be less than mid. else hi = mid; } return lo; } int upper_bound_(vector arr, int target){ int lo = 0; int hi = arr.size()-1; while(lo target) hi = mid-1; // Our index needed may be this index mid or may be greater than mid. else lo = mid; } return lo; } /* Rotated sorted array will look something like this only at pivot arr[pivot] > arr[pivot+1] / / / <- case 1 (mid > arr[0]) / / / <- case 2 (mid < arr[0]) / ex. {4, 5, 6, 7, 0, 1, 2} */ int find_pivot(vector &arr) { int lo = 0, hi = arr.size()-1; while(lo < hi) { int mid = (lo+hi)/2; if(arr[mid] > arr[0]){ if(arr[mid] > arr[mid+1]) return mid; else lo = mid+1; } else{ if(arr[mid-1] > arr[mid]) return mid-1; else hi = mid-1; } } return lo; } int pivotedBinarySearch(vector &arr, int target){ // Task 1: Find the highest elements index // Task 2: Simple binary search in one of the ranges int pivot = find_pivot(arr); vector :: iterator it; if(target >= arr[0]) it = lower_bound(arr.begin(),arr.begin()+pivot,target); else it = lower_bound(arr.begin()+pivot+1, arr.end(),target); if(*it != target) return -1; else return it-arr.begin(); } int main(){ // Array is sorted then rotated task is to find index of key element. vector arr = { 5, 6, 7, 8, 9, 10, 1, 2, 3 }; cout << "Index of the element is : "<< pivotedBinarySearch(arr, 2); } ================================================ FILE: Adhoc + Basic/binary_search_III.cpp ================================================ #include using namespace std; int lowerBound(vector arr, int target) { int left = 0; int right = arr.size() - 1; int result = -1; while (left <= right) { int mid = left + (right-left)/2; // To help with out of bounds if (arr[mid] >= target) { // we want the value in ans if the target exists result = mid; right = mid - 1; } else { left = mid + 1; } } return result; } int upperBound(vector arr, int target) { int left = 0; int right = arr.size() - 1; int result = -1; while (left <= right) { int mid = left + (right-left)/2; // To help with out of bounds if (arr[mid] > target) { // we want a greater than target value. result = mid - 1; right = mid - 1; } else { left = mid + 1; } } return result; } ================================================ FILE: Arrays/MedianOfSortedArrays.cpp ================================================ // Problem Link : https://leetcode.com/problems/median-of-two-sorted-arrays/ /* If we merge two arrays in sorted manner the central values will give us the median 1 4 5 2 6 7 8 9 1 2 4 5 6 7 8 9 -> (5+6)/2 The left half and right half of this combined array has elements from both arrays 1 4 5 | INT_MAX <- from arr1 (INT_MAX because there was no other element to right, similarly INT_MIN if there's no element to left) 2 | 6 7 8 9 <- from arr2 all elements in the left half should be smaller than all elements on right in this configuration so basically 5<6 && 2 using namespace std; class Solution { public: double findMedian(vector&a,vector&b){ int m=a.size(); int n=b.size(); int l=0,r=m; while(l<=r){ int partx=l+(r-l)/2; int party=(m+n+1)/2-partx; int maxlx=(partx==0)?INT_MIN:a[partx-1]; int minrx=(partx==m)?INT_MAX:a[partx]; int maxly=(party==0)?INT_MIN:b[party-1]; int minry=(party==n)?INT_MAX:b[party]; if(maxlx<=minry&&maxly<=minrx){ if((m+n)%2==0) return (double)(max(maxlx,maxly)+min(minrx,minry))/2; else return (double)(max(maxlx,maxly)); }else if(maxlx>minry) r=partx-1; else l=partx+1; } return -1.0; } double findMedianSortedArrays(vector& nums1, vector& nums2) { if(nums1.size() using namespace std; vector findMedian(vector &arr, int n){ // To store the medians vector medians; // max heap priority_queue lo; //min heap priority_queue, greater> hi; for(int i = 0; i < n; i++){ int num = arr[i]; // Add to max heap lo.push(num); // Balancing step, that is inserting the current element at its position that is either less than median or more than median value hi.push(lo.top()); lo.pop(); // Maintain size property, as 'lo' can have utmost one more element than 'hi' or both have equal number of elements if (lo.size() < hi.size()) { lo.push(hi.top()); hi.pop(); } int median; // For odd number of elements if(lo.size() > hi.size()){ median = lo.top(); } // For even number of elements else{ median = (lo.top() + hi.top())/2; } medians.push_back(median); } return medians; } ================================================ FILE: Arrays/MonotonicStack.cpp ================================================ /** * @file MonotonicStack.cpp * @author Nisarg * @brief A monotonic stack is a stack whose elements are monotonically increasing or descreasing. * Sometimes we store the index of the elements in the stack and make sure the elements corresponding to those indexes in the stack forms a mono-sequence * * @question Find next smaller/greater element for each element in O(n) Time complexity. * */ #include using namespace std; vector nextGreaterElement(vector arr) { stack > stck; int i,n = arr.size(); vector ans(n); for(i=0;i1 if(stck.empty()) { stck.push({arr[i], i}); continue; } while(!stck.empty() && stck.top().first < arr[i]) { ans[stck.top().second] = arr[i]; stck.pop(); } stck.push({arr[i],i}); } while(!stck.empty()) { ans[stck.top().second] = -1; stck.pop(); } return ans; } // Stack always array indices where values are in increasing order. vector nextSmallerElement(vector arr) { stack stck; int i,n = arr.size(); vector ans(n, -1); for(i=0;i arr = {1, 7, 2, 3, 1, 8}; vector nextGreater = nextGreaterElement(arr); cout << "\nNext Greater Element: "; for (auto ele: nextGreater) cout << ele << " "; vector nextSmaller = nextSmallerElement(arr); cout << "\nNext Smaller Element: "; for (auto ele: nextSmaller) cout << ele << " "; } ================================================ FILE: Arrays/Sliding Window Max.cpp ================================================ /** * https://leetcode.com/problems/sliding-window-maximum/solutions/5503612/best-code-in-c-must-see-easy-to-understand-beats-98-48-solution/ Find max value in each range of k size. */ ================================================ FILE: Arrays/TrappingRainwater.cpp ================================================ #include using namespace std; class Solution { public: int trap(vector& height) { int n = height.size(); int left=0; int right=n-1; int res=0; int maxleft=0, maxright=0; while(left<=right){ if(height[left]<=height[right]){ if(height[left]>=maxleft) maxleft=height[left]; else res+=maxleft-height[left]; left++; } else{ if(height[right]>=maxright) maxright= height[right]; else res+=maxright-height[right]; right--; } } return res; } }; /* we are concerned with maximum height on left and that on right, so we can maintain two prefix and suffix arrays to precompute the max_left and max_right and the answer will be min(max_left,max_right) - curr_height But since we are only concerned with the minimum of the left and right max we can get rid of the extra space */ ================================================ FILE: Arrays/readme.md ================================================ Deletion in a vector takes O(1) time if order doesn't matter. Delete ith indexed value. ``` swap(arr[i], arr[n-1]); arr.pop_back(); ``` ================================================ FILE: Bit-mask/Bitmask_Basic.cpp ================================================ // Reference -> https://www.youtube.com/watch?v=7FmL-WpTTJ4 // We are using bitmask to store the numbers between 1 and 10 (in integers) [Each bit represents a subset of intergers 1 to 10]. 15 represents set with 1,2,3,4.] // left shifting (x<>y) is equivalent to dividing x with 2^y. #include using namespace std; // If element is present it will get deleted and if its not there it will get added void erase_or_add(int n, int& subset) { subset = subset ^ 1<<(n-1); } void display(int subset) { cout<<"The subset is: "; // i is the ith bit from right to left // 0th bit represents 1 for(int i=0;i<9;i++) { if(1< using namespace std; void LCS(string a, string b) { int n = a.size(), m = b.size(); vector > dp(n+1, vector (m+1, 0)); for(int i = 1; i <= n; i++) { for(int j = 1; j <= m; j++) { if(a[i-1] == b[j-1]) { dp[i][j] = dp[i-1][j-1] + 1; } else { dp[i][j] = max(dp[i-1][j], dp[i][j-1]); } cout << dp[i][j] << " "; } cout << endl; } cout << "Longest comman string's length is " << dp[n][m] << endl; int i = n+1, j = m+1; string ans = ""; while (i > 0 || j > 0) { if (a[i-1] == b[j-1]) { ans += a[i-1]; i--; j--; } else { if (dp[i-1][j] < dp[i][j-1]) j--; else i--; } } reverse(ans.begin(), ans.end()); cout << "Longest common subsequence is " << ans << endl; } void LCS_SpaceOptmized(string a, string b) { int n = a.size(), m = b.size(); vector dp(m+1, 0); vector prev(m+1, 0); for(int i = 1; i <= n; i++) { for(int j = 1; j <= m; j++) { if(a[i-1] == b[j-1]) { dp[j] = prev[j-1] + 1; } else { dp[j] = max(dp[j-1], prev[j]); } } prev = dp; } cout << "Longest comman string's length is " << prev[m] << endl; } int main() { string str1 = "abcda"; string str2 = "abcbcba"; int m = str1.length(); int n = str2.length(); LCS(str1, str2); LCS_SpaceOptmized(str1, str2); return 0; } ================================================ FILE: DP/LIS.cpp ================================================ /* Longest Increasing Subsequence Complexity for LIS Algo -> O(NlogN) N-number of elements */ #include using namespace std; // NOTE : aux is not necesserily the LIS but its length is same as LIS int length_LIS(int arr[], int n) { vector aux; //auxiliary vector stores the array elements likely to be LIS for(int i = 0; i < n; i++) { // Change lower_bound to upper_bound for non-decreasing subsequence auto itr = lower_bound(aux.begin(), aux.end(), arr[i]); if (itr == aux.end()) aux.push_back(arr[i]); // No element is larger than arr[i] else *itr = arr[i]; // replace the element in aux with elemwnt just smaller than it. } return aux.size(); } // This is O(n^2) soln which can be eventually used to find the the exact LIS int lengthLIS1(vector arr) { int n = arr.size(); vector dp(n, 1); // dp[i] = 1 as LIS can be itself for(int i=0; i dp(n, 1); // dp[i] = longest sub seq till i where ith element is part of it int ans = 0; for (int i = 0; i < n; i++) { for (int j = 0; j < i; j++) { if (arr[i] > arr[j]) dp[i] = max(dp[i], dp[j] + 1); } } for(int i = 0; i < n; i++) ans = max(ans, dp[i]); cout << "Length of LIS is " << ans << endl; } // Time Complexcity O(N log N) void find_LIS_Optimizd(int arr[],int n) { vector aux(n, 0); vector> parent(n); aux[0] = arr[0]; parent[0].push_back(arr[0]); int aux_size = 1; for (int i = 1; i < n; i++) { auto it =lower_bound(aux.begin(), aux.begin() + aux_size, arr[i]); if (it == aux.begin() + aux_size) { aux[aux_size] = arr[i]; parent[aux_size] = parent[aux_size - 1]; parent[aux_size].push_back(arr[i]); aux_size++; } else { if (*it != arr[i]) { aux[it- aux.begin()] = arr[i]; parent[it - aux.begin()][parent[it - aux.begin()].size() - 1] = arr[i]; } } } cout << "length " << aux_size << endl; for (auto x : parent[aux_size - 1]) { cout << x << " "; } } int main() { int arr[] = { 10, 22, 9, 33, 21, 50, 41, 60 }; int n= sizeof(arr)/sizeof(int); // Strictly increasing sub sequence cout << "Length of LIS is :" << length_LIS(arr,n) << endl; // Print the LIS length_LIS(arr,n); find_LIS(arr, n); } // Intersting question : // Given arr1[N], arr2[M] 1 using namespace std; /* solution is based on gap strategy Reference --> https://www.youtube.com/watch?v=WpYHNHofwjc Every diagonal of the matrix can be uniquely identified by a gap value which represents the gap between i and j The gap 0 basically represents the individual elements which are themselves palindromes ex. str = abcda gaps = a | b | c | d | a ==> 4 gaps (cnt of |) Now for any particular i,j it is a palindrome if str from i+1 to j-1 is a palindrome and characters at i and j are equal So, dp[i][j] = dp[i+1][j-1] && str[i]==str[j] Here dp[i+1][j-1] represents the diagonally lower element which we have already computed in previous gap iterations */ class Solution { public: string longestPalindromeicSubString(string s) { int n = s.length(); bool dp[n][n]; memset(dp,false,sizeof(dp)); int start = -1; int end = -1; for(int gap=0;gap using namespace std; // Longest common sequence between two strings // If a[i] == b[j] dp[i][j] = dp[i-1][j-1] + 1; else max(dp[i-1][j], dp[i][j-1]) int LCS(string a, string b, int n, int m) { vector > dp(n + 1, vector(m + 1, 0)); for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) { if (a[i - 1] == b[j - 1]) dp[i][j] = 1 + dp[i - 1][j - 1]; else dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]); } } return dp[n][m]; } // Trying to mimic the above code using same thing using two pointers int longestPalindromeSubseq(string str) { int i, j, n = str.size(); vector > dp(n + 1, vector(n + 1, 0)); // dp[i][j] denotes the string i to j (inclusive) for (i = n - 1; i >= 0; i--) { dp[i][i] = 1; for (j = i+1; j < n; j++) { dp[i][j] = max(dp[i + 1][j], dp[i][j - 1]); if (str[i] == str[j]) { dp[i][j] = max(dp[i][j], dp[i + 1][j - 1] + 2); } } } return dp[0][n-1]; } // Optimized above solution to use O(N) space int longestPalndromeSubsequenceOptimzed(string str) { int n = str.size(); vector dp(n, 0), dpPrev(n, 0); // prev denotes the prev row of above solution. for (int i = n - 1; i >= 0; --i) { dp[i] = 1; for (int j = i+1; j < n; ++j) { if (str[i] == str[j]) { dp[j] = dpPrev[j-1] + 2; } else { dp[j] = max(dpPrev[j], dp[j-1]); } } dp.swap(dpPrev); } return dpPrev[n-1]; } int longestPalindromeSubseqUsingLCS(string s) { string s2 = s; reverse(s2.begin(), s2.end()); return LCS(s, s2, s.size(), s.size()); } int main() { string str = "abccefba"; cout << "Longest Palindromic subseq using LCS: " << longestPalindromeSubseqUsingLCS(str) << endl; cout << "Longest Palindromic subseq: " << longestPalindromeSubseq(str) << endl; cout << "Longest Palindromic subseq with O(N) Space Optmization: " << longestPalndromeSubsequenceOptimzed(str) << endl; } ================================================ FILE: DP/MatrixChainMulti.cpp ================================================ // We use this techinique when we have to put brackets in the given list based on some condn. // This solution is used when the order in which we pick a element determines the answer. // Very good que: https://leetcode.com/problems/burst-balloons/ ================================================ FILE: DP/PalindromicCuts.cpp ================================================ /** * @file PalindromicCut.cpp * @author Nisarg Gogate * @brief Cases when we want to divide array/string into parts and maximize/minimize * something about those parts. We can try MCM * * Ex. Find min numbers of cuts needed such that each substring is a palindrome. * @ref https://leetcode.com/problems/palindrome-partitioning-ii/description/ */ #include using namespace std; int SIZE = 2002; vector> dp(SIZE, vector(SIZE, -1)); bool isPalindrome(string str) { int i = 0, j = str.size() - 1; while (i < j) { if (str[i] != str[j]) return false; i++, j--; } return true; } /** * @brief Usually MCM time complexcity is O(n^3) but here as we are checking if it's * a palindrome time complexcity is O(n^4) */ int findCuts(string str, int l, int r) { if (dp[l][r] != -1) return dp[l][r]; // String can't be cut if it's length is already less than 1 if (l >= r) return dp[l][r] = 0; if (isPalindrome(str.substr(l, r - l + 1))) return 0; int ans = r - l; // NOTE: k should not be equal to r to avoid inf loop for (int k = l; k < r; k++) { int left = dp[l][k] == -1 ? findCuts(str, l, k) : dp[l][k]; int right = dp[k + 1][r] == -1 ? findCuts(str, k + 1, r) : dp[k + 1][r]; ans = min(ans, left + right + 1); } return dp[l][r] = ans; } /** * @brief Idea is to find if a string is palindrom or not in O(1) using dp * Also, we don't really need to know number of plindromes between i and j. * * Here dp[i] represents number of palindromes from 0->i. * So, dp[i] = dp[k] + 1 where k->i is a plindrome. * * Time Complexcity: O(n^2), Space Complexcity: O(n^2) */ int findCutsOptimized(string str) { int n = str.size(); vector dp(n, 0); vector> isPalindrome(n, vector(n, false)); for (int len = 1; len <= n; ++len) { for (int i = 0; i <= n - len; ++i) { int j = i + len - 1; if (str[i] == str[j] && (len <= 2 || isPalindrome[i + 1][j - 1])) { isPalindrome[i][j] = true; } } } for (int i = 0; i < n; ++i) { if (isPalindrome[0][i]) { dp[i] = 0; } else { dp[i] = i; // suppose we need to cut at each index for (int j = 0; j < i; ++j) { if (isPalindrome[j + 1][i]) { dp[i] = min(dp[i], dp[j] + 1); } } } } return dp[n - 1]; } /** * @brief We take advantage of property that palindrome is same from front and back * We * * Time Complexcity: O(n^2), Space Complexcity: O(n) * * @param str * @return int */ int findCutsMostOptimized(string str) { int n = str.size(); vector dp(n+1); for (int i = 0; i <= n; i++) dp[i] = i-1; // note dp[0] will be set -1. This helps us with a cleaner code for(int mid = 0; mid < n; mid++){ //palindrome of odd lengths 1,3,5... for(int len = 0; mid-len >= 0 && mid+len < n; len++) if(str[mid-len] == str[mid+len]) dp[mid+len+1] = min(dp[mid+len+1], dp[mid-len]+1); //palindrome of even lengths 2,4,6... for(int len = 0; mid-len >= 0 && mid+len+1 < n; len++) if(str[mid-len] == str[mid+len+1]) dp[mid+len+2] = min(dp[mid+len+2], dp[mid-len]+1); } return dp[n]; } int main() { string str = "aabacd"; cout << "Minimum cuts needed " << findCuts(str, 0, str.size() - 1) << "\n"; } ================================================ FILE: DP/digit_dp.cpp ================================================ // Reference -> https://www.youtube.com/watch?v=heUFId6Qd1A // F(x) returns boolean value // General -> How many integers x in range [0,R] obey F(x) // Example -> Find cnt of numbers betn L and R which have a sum of digits = x // 1 <= L <= R <= 10^18 // 1 <= X <= 180 #include using namespace std; // Max no of dights in a number be 100(Not needed) int dp[101][181][2]; // boolena value tight stores checks if we can place any number at indx(R.size()-n) or we need we can place till ub int digit_dp(string R,int n,int sum,bool tight) { if(sum < 0) return 0; if(n==0) { if(sum == 0) return 1; return 0; } if(dp[n][sum][tight] != -1) return dp[n][sum][tight]; // ub is upper bound till which digit we can use at that particular index int ub = 9,ans=0; if(tight) ub = (R[R.size()-n]-'0'); for(int i=0;i<=ub;i++) { // Once a number is non tight it won't ever be tight in future // A tight will be tight only if we keep on passing the higest number possible at that indx ans += digit_dp(R,n-1,sum-i,tight&(i==ub)); } return dp[n][sum][tight] = ans; } int main() { string L = ""; string R = "490447834749"; int x = 20; memset(dp,-1,sizeof dp); cout< https://www.youtube.com/watch?v=QukpHtZMAtM&list=PLb3g_Z8nEv1icFNrtZqByO1CrWVHLlO5g&index=4 // Reference -> https://www.thecrazyprogrammer.com/2017/05/travelling-salesman-problem.html // Time Complexcity -> O(n^2 * 2^n) // Space Complexcity -> O(2^n * n) // NOTE : Whenever we feel a need to pass a subset of set we can use this technique of digit dp // Que. Find minimum distance to travel if travellers wishes to visit every city atleast once and reach back to his starting location at the end #include using namespace std; #define MAX 9999 int n=4; // Number of the places want to visit //Next distan array will give Minimum distance through all the position int distan[10][10] = { {0, 10, 15, 20}, {10, 0, 35, 25}, {15, 35, 0, 30}, {20, 25, 30, 0} }; int all_visited = (1< // Time Complexity: O(V + E) // A slight modification of question: Find 2nd fastest way of reaching from source to destination. in Undirected ascyclic graph. // Fastest way is using normal BFS. Here we'll ne two dist arrays. dist1[]stroring 1st time we encounter a num. dist2[] we encountering 2nd time. //https://www.youtube.com/watch?v=_rnQKrA9xzA&t=436s&ab_channel=codestorywithMIK using namespace std; #define LIM 1007 vector adj[LIM]; // vector dist(LIM,-1); // vector parent(LIM,-1); int visited[LIM]; void addEdge(int u, int v) { adj[u].push_back(v); adj[v].push_back(u); } void bfs(int src) { queue q; int d=0; // dist[src] = d; // parent[src] = -1; q.push(src); visited[src]=true; while(!q.empty()) { int u = q.front(); q.pop(); cout<>V>>E; for(i=0;i>u>>v; addEdge(u,v); } cout<<"Enter source node for iterative bfs: "; cin>>src; cout<<"BFS=> "; bfs(src); cout< https://www.youtube.com/watch?v=FtN3BYH2Zes Minimum distance of src from every other node present in graph Complexity for Bellman Ford's Algo -> O(E*V) E-Edges V-Vertices */ #include #define LIM 3000 #define INF 1e5+3 using namespace std; //NOTE: Here reprentation of graph is done a bit differnetly typedef pair pii; vector> G(LIM,vector(3)); vector min_dist(LIM,INF); int V,E; /* IMP NOTE: If there is a cycle with total sum negative then this algo WON'T WORK We baically relax the edges V-1 times */ void bellman_ford(int src) { min_dist[src] = 0; int u,v,k; for(k=0;k min_dist[u]+wt) { cout << "There is a negtive cycle\n"; break; } } } int main() { int i,src=0,u,v,wt; cout<<"Enter number of vertices and edges: "; cin>>V>>E; cout<>u>>v>>wt; G[i][0] = u; G[i][1] = v; G[i][2] = wt; } cout<<"Enter the source node: "; cin>>src; bellman_ford(src); cout< using namespace std; #define LIM 1007 typedef enum {WHITE,GREY,BLACK} col; // we try ro color whole graph in 2 colors grey and black vector adj[LIM]; vector color(LIM,WHITE); void addEdge(int u, int v) { adj[u].push_back(v); adj[v].push_back(u); } void bfs() { queue q; int d=0; for(int i=1;i>V>>E; for(i=0;i>u>>v; addEdge(u,v); } // Printing color of each node in graph bfs(); } ================================================ FILE: Graph/Bipartite_matching.cpp ================================================ /** * @file Bipartite_matching.cpp * @author Nisarg * @brief Question: Given n job appplicants and m jobs. Given ith applicant with letter from jth job * Find maximum number of job applicants which can get a job. jobs[i][j] = 1 / 0 * * @ref: https://www.geeksforgeeks.org/maximum-bipartite-matching/ * @ref: https://cp-algorithms.com/graph/kuhn_maximum_bipartite_matching.html * @ref: https://leetcode.com/problems/maximum-number-of-accepted-invitations/solutions/1978859/python-hungarian-algorithm-easy-to-understand/ */ #include using namespace std; int jobs = 6, applicants = 6; vector > G; vector currentMatching(jobs, -1); // Job i mapped with currentMatching[i] applicant. vector visited(applicants); // Usual use so that dfs doesn't visit same vertex again /** * Main idea behind the logic is a job applicant will only leave job if he/she gets some other job. * * @return bool : true a new match is added */ bool findMaxBiPartiteMatching(int u) // applicant { if (visited[u]) // if applicant is already assigned or checked no need to recheck return false; visited[u] = true; // Checking if vth job if already selected by some applicant for (auto v : G[u]) { // if current matching is available for v or if v can find some other job // checking if selected applicant for job v can find some other job if ( currentMatching[v] == -1 || findMaxBiPartiteMatching(currentMatching[v]) ) { currentMatching[v] = u; return true; } } return false; } int main() { G = { {1, 2}, // Applicant 0 has {1, 2} job offers {0, 3}, // Applicant 1 has {0, 3} job offers {2}, {2, 3}, {}, {5} }; int ans = 0; for (int applicant = 0; applicant < applicants; applicant++) { visited.assign(applicants, false); if(findMaxBiPartiteMatching(applicant)) ans++; } cout << "Max num of G matching with applicants is " << ans; } ================================================ FILE: Graph/DFS.cpp ================================================ /* We can peform multisorurce bfs also for the problems of type 1. there are k hospitals and n cities and they are connected so find closest hostila form each city Add all hospitals as src and do bfs on unvisited nodes so ... Time Complexity: O(V + E) */ #include #define LIM 3000 #define INF 1e5+3 using namespace std; vector adj[LIM]; bool visited[LIM]; void addEdge(int u, int v) { adj[u].push_back(v); adj[v].push_back(u); } void dfs_iterative(int src) { memset(visited,0,sizeof(visited)); stack stck; stck.push(src); while(stck.size()) { int u=stck.top(); stck.pop(); visited[u]=true; cout<>V>>E; for(i=0;i>u>>v; addEdge(u,v); } cout<<"Enter source node for iterative dfs: "; cin>>src; cout<<"Iterative_DFS=> "; dfs_iterative(0); cout<>src; cout<<"Recursive_DFS=> "; } ================================================ FILE: Graph/FloydWarshall.cpp ================================================ /** * @file FloydWarshall.cpp * @author Nisarg * @brief Multi Source shortest path algorithm. Find shortest paths from all nodes to all other nodes. * Logic: dist[i][j] = min (dist[i][j]],dist[i][k] + dist[k][j]) * Time complexity: O(V^3) * @date 2024-07-28 */ #define INF 1e5+3 #include using namespace std; void findShortestDist(vector>& matrix) { int n = matrix.size(), i, j, k; // initialize matrix with INF dist where no roads are available // initialize matrix with 0 dist where i == j for (i = 0; i < n; i++) { for (j = 0; j < n; j++) { if (matrix[i][j] == -1) matrix[i][j] = INF; if (i == j) matrix[i][j] = 0; } } // Floyd Warshall's algorithm for(k = 0; k < n; k++) for(i = 0; i < n; i++) for(j = 0; j < n; j++) matrix[i][j] = min(matrix[i][j], matrix[i][k] + matrix[k][j]); } int main() { int V = 4; vector > matrix(V, vector(V, -1)); matrix[0][1] = 2; matrix[1][0] = 1; matrix[1][2] = 3; matrix[3][0] = 3; matrix[3][1] = 5; matrix[3][2] = 4; findShortestDist(matrix); cout << "Following matrix shows the shortest distances between every pair of vertices \n"; for (int i = 0; i < V; i++) { for (int j = 0; j < V; j++) { if (matrix[i][j] == INF) cout << "INF "; else cout << matrix[i][j] << " "; } cout << endl; } } ================================================ FILE: Graph/README.md ================================================ # Graphs Minimum Spanning Tree - **Prim's Algorithm**: Add `{wt, node}` to min heap to visit all nodes only once. Shortest Distance from `src` node to all nodes in Graph - **Dijkstra Algorithm**: Greedy approach choose the closest node from each node and store in min heap. *[+ve weights]*. - **Bellman Ford**: Loop V times over all edges in graph and set `dist[v] = min(dist[v], dist[u]+wt(u,v))`. *[-ve weights]* Shortest Distance between all pairs of nodes in Graph - **Floyd Warshall Algorithm**: For every path which passes through k, `dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j])` Dungeon Break: https://leetcode.com/problems/dungeon-game/description/ Really good question ================================================ FILE: Graph/cycleDetection.cpp ================================================ /** * @file cycleDetection.cpp * @author Nisarg * @date 2024-07-27 * * Detect cycle in directed and adirected graphs */ #include #define LIM 1007 using namespace std; vector G[LIM]; // Other way of doing this is by bipartiate coloring bool isCyclicInDirectedGraph(int n, vector inDegree) { int i; queue q; // NOTE: it stores the topo sorted order for(i=0;i> n >> edges; vector inDegree(n); for(int i=0;i> u >> v; G[u].push_back(v); inDegree[v]++; } if(isCyclicInDirectedGraph(n, inDegree)) cout << "Cycle found in directed Graph" << endl; } ================================================ FILE: Graph/dijkstra.cpp ================================================ /* A minimum distance of src from every other node present in graph with all non-negative weights (optimized algo) OR Negative weighted a-cyclic graph (Non-optimized Algo) Complexity for dijktra's Algo -> O((V + E) log V) E-Edges V-Vertices We may add same node multiple times, hence total elements in a heap might be E. Hence, log(E). Intreasting thing is to E = V*(V-1) => 2*log(V). Slight modification: Think of adding a virtual node which joins an edge to each node. [Similar to multi source BFS] Dikjtras can be applied 3-4 times... you reverse graph... node a to src and dest dist https://leetcode.com/problems/minimum-weighted-subgraph-with-the-required-paths/description/ */ #include #define LIM 3000 #define INF 1e5+3 typedef pair pii; using namespace std; //NOTE: Global variables are initailized to 0 vector adj[LIM]; vector min_dist(LIM,INF); //Each node in adj list represnts vertex and weight void addEdge(int u, int v, int wt) { adj[u].push_back({v,wt}); adj[v].push_back({u,wt}); } void dijktra(int src) { //MIN HEAP // Keep distace or weight in first plce and indx in second priority_queue, greater > pq; for(int i=0;i min_dist[curr]) continue; for(auto u : adj[curr]) { int next = u.first; int d = u.second; //If previous distance is more than the new distance if(min_dist[next] > min_dist[curr]+d) { pq.push({ d + min_dist[curr], next }); min_dist[next] = d+ min_dist[curr]; } } } } int main() { int V,i,E,src,u,v,wt; cout<<"Enter number of vertices and edges: "; cin>>V>>E; cout<>u>>v>>wt; addEdge(u,v,wt); } cout<<"Enter the source node: "; cin>>src; dijktra(src); cout< #define LIM 3000 #define INF 1e5+3 using namespace std; typedef pair pii; vector adj[LIM]; bool visited[LIM]; //Each node in adj list represnts vertex and weight void addEdge(int u, int v, int wt) { adj[u].push_back({v,wt}); adj[v].push_back({u,wt}); } int prim() { //MIN HEAP priority_queue, greater > pq; int mst_sum=0; int curr_dist=0; //Lets assume we start from 0th node pq.push({curr_dist,0}); while(pq.size()) { //we get the smallest possible distance on top of pq int curr_node=pq.top().second; int curr_dist=pq.top().first; pq.pop(); //if already visited the it must be connected to smallest possible value if(visited[curr_node]) continue; visited[curr_node]=true; mst_sum += curr_dist; for(auto u : adj[curr_node]) { //We push in all the possible adjecent nodes from curr_node if(!visited[u.first]) pq.push({u.second,u.first}); } } return mst_sum; } int main() { int V,E,i,src,u,v,wt; cout<<"Enter number of vertices and edges: "; cin>>V>>E; cout<>u>>v>>wt; addEdge(u,v,wt); } cout<<"Minimum spanning tree sum: "; cout< https://cses.fi/problemset/task/1679 Time complexcity -> O(V+E) Space Complexcity -> O(V) */ // Alternate approach can be looking at the in-degree of each node // Step 1: Find in-degree of each node and maintain it in an array // step 2: if(indgree[i] == 0) put in queue (bfs) and add it in aur ans array // do bfs and which ever element we visit reduce its indegree // keep on checking while reducing indegree and if its zero add... REPEAT #include #define LIM 3000 #define INF 1e5+3 typedef enum {WHITE,GREY,BLACK} col; //white-no col using namespace std; int V,E; vector G[LIM]; vector visited(LIM,false); vector color(LIM,WHITE); bool notIsCyclic(int u) { color[u] = GREY; bool ans=true; for(auto v:G[u]) { if(color[v] == GREY) return false; if(color[v] == BLACK) continue; ans &= notIsCyclic(v); } color[u] = BLACK; return ans; } void dfs(int u, stack& stck) { visited[u] = true; for(auto v: G[u]) if(!visited[v]) dfs(v,stck); // NOTE : We insert element in stack after its dfs traversal. stck.push(u); } int main() { int i,j; cin>>V>>E; for(i=0;i> u >> v; G[u].push_back(v); } // Check for any cycle in graph for(i=1;i<=V;i++) if(color[i] == WHITE) if(!notIsCyclic(i)) { cout << "IMPOSSIBLE\n"; return; } // Adding elements to the stack if not visited stack stck; for(i=1;i<=V;i++) if(!visited[i]) dfs(i,stck); // Actually elements are adding in opposite order of topo sort but we // acces the elements in descending order as its a stack. for(;!stck.empty();stck.pop()) cout << stck.top() << " "; } ================================================ FILE: Graph/union_find_algo.cpp ================================================ /* Que: Given a list of operation makeFriends(a,b) and areFriends(a,b) These methods makes a and b friends or checks if they are friends. Time & Space complexcity if done by Graph O(n) & O(n) Time & Space complexcity in case of disjoint set O(m*4) & O(n) : m is the number of operations being performed on this dijoint set https://leetcode.com/problems/the-earliest-moment-when-everyone-become-friends Ref: https://www.youtube.com/watch?v=Kptz-NVA2RE */ #include using namespace std; vector parent; // Keeps track of group representative/parent vector sz; // Keeps track of num of elements in children below this node // Init the array with each element as it's parent void init(int n) { parent.resize(n); sz.resize(n); for (int i = 0; i < n; i++) { parent[i] = i; sz[i] = 1; } } // Finds parent of x then parent of parent of x and so on... // Along with path compression as on return it updates parent[x] int find(int x) { if (parent[x] == x) return x; return parent[x] = find(parent[x]); // remember to call it for parent[x] } // Joins sets of x to y. Based on the rank of parent for minimum time complexcity. void weightedUnion(int x, int y) { int xRoot = find(x); int yRoot = find(y); if (xRoot == yRoot) return; if (sz[xRoot] < sz[yRoot]) { parent[xRoot] = yRoot; sz[yRoot] += sz[xRoot]; } else { parent[yRoot] = xRoot; sz[xRoot] += sz[yRoot]; } } // n - number of fiends // m - number of operations/relations int main() { int i, n, m; cin >> n >> m; init(n); for (i = 0; i < m; i++) { string operation; int x, y; cin >> operation >> x >> y; if (operation == "makeFriend") { weightedUnion(x, y); } else if (operation == "isFriend") { if(find(x) == find(y)) cout << "Yes\n"; else cout << "No\n"; } } return 0; } ================================================ FILE: Greedy or DP (Problems)/Continuous_subarray_sum.cpp ================================================ // Link --> https://leetcode.com/problems/continuous-subarray-sum/ Find if is there any subarray with sum in multiple of k bool find(vector arr, int k){ set s; int sum=0; for(int i=0;i https://leetcode.com/problems/maximum-profit-in-job-scheduling/ // You're given the startTime, endTime and profit arrays, return the maximum profit // you can take such that there are no two jobs in the subset with overlapping time range. // 1 <= startTime[i] < endTime[i] <= 10^9 // NOT A GREEDY SOLN int jobScheduling(vector& startTime, vector& endTime, vector& profit) { int n = startTime.size(); vector> jobs; for (int i = 0; i < n; ++i) { jobs.push_back({endTime[i], startTime[i], profit[i]}); } // Sort according to end time of jobs sort(jobs.begin(), jobs.end()); // dp[i] stores maximum profit at time = i map dp = {{0, 0}}; for (auto& job : jobs) { // Finding the profit at largets end time before current job's start iem int cur = prev(dp.upper_bound(job[1]))->second + job[2]; if (cur > dp.rbegin()->second) dp[job[0]] = cur; } return dp.rbegin()->second; } // Link -->https://practice.geeksforgeeks.org/problems/job-sequencing-problem-1587115620/1# // N jobs takes 1 unit of time to complete and jth job has job[j] as deadline. // Find max profit? /* * Sort according to the profits (decreasing) * Do the process as late as possible (Close to deadline) * U have the ans... */ ================================================ FILE: Greedy or DP (Problems)/Kadane.cpp ================================================ // Find max_sum of sub array // Question? Why should curr_sum start with arr[i] and not with something before ith index? // Assume started from start => Case 1: (some -ve sum) + arr[j] - we will already started from arr[j]. => Case 2: (Some +ve sum) + arr[j] - It's already part of curr_sum. int kadane(vector arr) { int n = arr.size(),i,ans_sum=0,curr_sum = arr[0]; for(i=1;i arr) { int ans = arr[0],max_val=arr[0],min_val=arr[0]; for(int i=1;i arr) { int i,n=arr.size(),prev_max = 0,ans=0; // TRICK - arr[i]+i + arr[j]-j is to be maximized for(i=0;i Time Complexcity O(n logn) */ #include using namespace std; // Return The sequence which satisfies the given condition vector> queue_reconstruction(vector> people) { // Observations - // We need to count people with height taller or equal to in front of them // Smaller person is completely irrelevant // For smallest person all persons are greater than him sort(people.begin(),people.end(),[](pair p1,pair p2){ return p1.first>p2.first or (p1.first == p2.first and p1.second> ans; for(int i=0;i using namespace std; int min_jump(vector arr) { int n = arr.size(),i; int range_of_jump = arr[0]; // This is the index upto which we can reach int max_reachable_index = arr[0]; // Next maximum reachable index from current range (1 more jump will be neede) int jump = 1; // We have already made our 1st jump for(i=1;i> n; vector arr(n); for(auto &it:arr) cin >> it; cout << min_jump(arr) << "\n"; } ================================================ FILE: Greedy or DP (Problems)/variations.txt ================================================ 1. Find maximum no. of intervals to select with no overlap. (Jump Scheduling - I) --> Jump Problem (DP but like Kedans) 2. Find minimum no. of intervals to select with minimum overlap. (Jump -II) --> DP solution (Job Scheduling problem) 3. Find maximum no. of intervals which overlap at a point? (Maximum no. of train platforms problem) --> Use a counter variable and add 1 when an interval starts and subtract 1 when an interval ends. max of counter is ans. ================================================ FILE: Matrix or Backtracking(Problems)/Max_Submatrix_with_LT_Ksum.cpp ================================================ // Maximum size square Sub-Matrix with sum less than or equals to K // Link -> geeksforgeeks.org/maximum-size-square-sub-matrix-with-sum-less-than-or-equals-to-k/ // Step 1: Find Prefix matrix sum[i][j] = arr[i-1][j-1]+sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1] // Step 2: Iterate over all i and j (N^2) // Step 3: Do binary search over all possible square sizes. min(i,j); // Step 4: Check if square sum is less than equals to k // Dungeon Game Reach n,m from 1,1 and healtmust be always +ve while moving. // Find starting health // https://leetcode.com/problems/dungeon-game/ // Crux --> start from n-1,m-1 boz we need to know what will be elements next to know what to choose ================================================ FILE: NumberTheory/RandomNum.cpp ================================================ /** * @file RandomNum.cpp * @author Nisarg Gogate * * Finding random number between 0 and n-1 * 1. rand() % n - It gives a random number but it's not evenly distributed. * 2. double num = rand() / RAND_MAX; * num * n-1 will be truly random. * * Q. Find weighted random number index based on the weight. * https://leetcode.com/problems/random-pick-with-weight/ * As we can't really add number multiple times to array (space issue), * we can add it as a prefix sum. look at this prefix sum from left. we see a array same * as the adding number multiple times. Getting numbe in (log n) with lower_bound. */ #include using namespace std; class Solution { public: vector prefix; Solution(vector& w) { prefix.push_back(w[0]); for(int i=1;i using namespace std; class LRUCache { int capacity; list> dq; // key, value pair // store references of key in cache unordered_map>::iterator> mp; public: LRUCache(int capacity) { this->capacity = capacity; } int get(int key) { if (mp.find(key) == mp.end()) return -1; int value = mp[key]->second; dq.erase(mp[key]); dq.push_front({key, value}); mp[key] = dq.begin(); return value; } void put(int key, int value) { if (mp.find(key) == mp.end()) { if (dq.size() == capacity) { pair last = dq.back(); dq.pop_back(); mp.erase(last.first); } } else { dq.erase(mp[key]); } dq.push_front({key, value}); mp[key] = dq.begin(); } }; // Driver Code int main() { LRUCache ca(4); ca.put(1, 2); ca.put(2, 3); ca.put(3, 2); ca.put(1, 2); cout << ca.get(4) << "\n"; ca.put(4, 1); cout << ca.get(4) << "\n"; ca.put(5, 6); return 0; } ================================================ FILE: README.md ================================================ # Algorithm Implementations We have not written all of these algos ourselves. This is merely a small collection of easy and beautiful solutions to complex problems. We have added reference links and questions on top of each file for further references. Feel free to star mark and fork :D ``` Common time complexities Let n be the main variable in the problem. If n ≤ 12, the time complexity can be O(n!). If n ≤ 25, the time complexity can be O(2n). If n ≤ 100, the time complexity can be O(n4). If n ≤ 500, the time complexity can be O(n3). If n ≤ 104, the time complexity can be O(n2). If n ≤ 106, the time complexity can be O(n log n). If n ≤ 108, the time complexity can be O(n). If n > 108, the time complexity can be O(log n) or O(1). ``` ## Features - Quick access to segregated codes. - Easy to understand yet small solutions. - Tries | Segment Trees (Trees), LRU Cache (OS). ## Authors - [Nisarg](https://github.com/nisarg0) - [Diplesh](https://github.com/dips4982) **Special Thanks to all the youtubers for the free and awesome content!!!** - [Katik Arora](https://www.youtube.com/user/MrHulasingh25) - [Utkarsh Gupta](https://www.youtube.com/channel/UCGS5ZzcSAymQbWZvNoKOFhQ) - [take U forward](https://www.youtube.com/channel/UCJskGeByzRRSvmOyZOz61ig) - [Pep-coding](https://www.youtube.com/channel/UC7rNzgC2fEBVpb-q_acpsmw) ## Support If you find some error do rasie issue [here](https://github.com/nisarg0/algos_implementation/issues). For support, email nisarggogate212@gmail.com or dipleshmankape@gmail.com ================================================ FILE: Range_queries/Mo's_algo.cpp ================================================ // Find number of elements ocuuring only once in range [L,R]. ================================================ FILE: Range_queries/Persisitant tree.cpp ================================================ ================================================ FILE: Range_queries/Range_Update(Difference_Array).cpp ================================================ // Reference link -> https://www.geeksforgeeks.org/difference-array-range-update-query-o1/ // Range update in time complexity O(1) and space complexity O(n) // Prefixsum and sufix sum is also a important technique but can be helpful only if // the operation in range is invertible(Ex add,sub or mul,div) can't be used for min,max or exor,and #include using namespace std; const int LIM = 1e3; vector difference(LIM,0); void init(int arr[],int n) { // 0th indx is init with value of 0th element in arr difference[0] = arr[0]; // after that nothinng should be added (precaution) difference[n] = 0; for(int i=1;in-1 or l>r) return; // we add x to lth indx so indirectly we add x to everthing after it difference[l] += x; // we need to subtract x from all the elements after r difference[r+1] -= x; } void print(int arr[], int n) { arr[0] = difference[0]; for(int i=1;i O(N) 2. Range sum query -> O(logN) for each level we only visit not more than four vertices 3. Update query -> O(logN) */ #include #define LIM 1007 using namespace std; int arr[LIM]; //input array int seg[4*LIM]={0}; //Seg tree children for index i are 2*i and 2*i+1 int lazy[4*LIM]={0}; //lazy tree children for index i are 2*i and 2*i+1 //initialization of segment tree void init_tree(int node_indx,int node_lower,int node_upper) { if(node_lower == node_upper) { seg[node_indx] = arr[node_upper]; return ; } int mid=(node_lower+node_upper)/2; init_tree(node_indx*2, node_lower, mid); init_tree(node_indx*2+1, mid+1, node_upper); seg[node_indx]=seg[2*node_indx]+seg[2*node_indx+1]; } // a,b is the range of query node_lower,node_upper is the range for particular node in seg_tree //a<=b and node_lower<=node_upper int range_query(int node_indx, int a, int b, int node_lower, int node_upper) { //range is between a,b if(a<=node_lower and node_upper<=b) return seg[node_indx]; //Not in range if(bnode_upper) return 0; //INT_MIN in case of min query int mid=(node_lower+node_upper)/2; //Intersecting on left side or right side or both return range_query(2*node_indx,a,b,node_lower,mid) + range_query(2*node_indx+1,a,b,mid+1,node_upper); } //updatepoint at a void update_point(int node_indx,int a,int node_lower, int node_upper, int val) { if(node_upper == node_lower) { seg[node_indx]+=val; return; } if(a < node_lower or a>node_upper) return ; int mid=(node_lower+node_upper)/2; // if a is between lower and mid if(node_lower >= a and a <= mid) update_point(2*node_indx,a,node_lower,mid,val); else update_point(2*node_indx+1,a,mid+1,node_upper,val); seg[node_indx]=seg[2*node_indx]+seg[2*node_indx+1]; } // a,b is the range of query node_lower,node_upper is the range for particular node in seg_tree // change values in range[a,b] by +val // make a copy of seg_tree called lazy and init with 0 /*void update_query(int node_indx,int a, int b, int node_lower, int node_upper, int val) { //we need to update changes in lower levels of this node if(lazy[node_indx]!=0) { seg[node_indx]+=(node_upper-node_lower+1)*val; if(node_upper!=node_lower) { lazy[node_indx*2]+=lazy[node_indx]; lazy[node_indx*2+1]+=lazy[node_indx]; } lazy[node_indx]=0; } //out of range if(bnode_upper or node_lower>node_upper ) return; //required range is between the range of segtree if(node_lower<=a and node_upper<=b) { seg[node_indx]+=(node_upper-node_lower+1)*val; if(node_lower!=node_upper) { lazy[node_indx*2]+=lazy[node_indx]; lazy[node_indx*2+1]+=lazy[node_indx]; } return; } //Intersecting on left side or right side or both int mid=(node_lower+node_upper)/2; update_query(2*node_indx,a,b,node_lower,mid,val); update_query(2*node_indx+1,a,b,mid+1,node_upper,val); seg[node_indx]=seg[node_indx*2]+seg[node_indx*2+1]; }*/ int main() { int i; //Intializing an array of size 10 with index itself //NOTE: We have used 1 based indexing for(i=1;i<=10;i++) { arr[i]=i; } //Initilize the Seg tree init_tree(1,1,10); //Range query[a,b] int a,b,val; cout<<"SUM: Enter range a,b: "; cin>>a>>b; cout<>a>>b; cout<>val; for(i=a;i<=b;i++) { update_point(1,i,1,10,val); } //Range query[a,b] cout<<"SUM: Enter range a,b: "; cin>>a>>b; cout< https://www.youtube.com/watch?v=2EpX9LkO2T0 // Refernece -> https://youtu.be/0jWeUdxrGm4 // NOTE : We can't update efficiently // Precomutation- O(NLogN) Query - O(LogN) // If query Function asked is Idempotent(F(a,a)=a) we can solve 1 query in O(1*op). op is time taken by the operator(gcd takes more time) // ex. max(a,a)=a , min, gcd, bitwie-or, bitwise-and, etc. #include using namespace std; // #define int long long const int LIM = (int)1e7; const int K = (int)(25); // jth column in ith row represents the value of function from i to i+2^j. // st[i][j] = f(i to i+2^j) int st[LIM][K+1]; //30 = log2 LIM int f(int a, int b) { return min(a,b); } // range [i,i+2^j−1] of length 2^j splits nicely into // the ranges [i,i+2^(j−1)−1] and [i+2^(j−1),i+2^(j−1)], both of length 2^(j−1). void init(int arr[],int n) { // length of ruery is 1 for (int i = 0; i < n; i++) st[i][0] = arr[i]; // j length query and strts from i for (int j = 1; j <= K; j++) for (int i = 0; i + (1 << (j-1)) <= n; i++) // Note : the loop termination condn. st[i][j] = f(st[i][j-1], st[i + (1 << (j - 1))][j - 1]); } int query_normal(int l,int r) { int ans = INT_MAX; // from 2^30m till 2^0 whch are the numbers we can subtract from r-l+1 till its not 0 // we basically add values of set bits from st. for(int i=K;i>=0;i--) { if((1< using namespace std; // Generates heap from ith node and it's children. void heapify(vector &arr, int n, int i) { int largest = i; // Initialize largest as root int l = 2 * i + 1; // left = 2*i + 1 int r = 2 * i + 2; // right = 2*i + 2 // If left child is larger than root if (l < n && arr[l] > arr[largest]) largest = l; // If right child is larger than largest so far if (r < n && arr[r] > arr[largest]) largest = r; // If largest is not root if (largest != i) { swap(arr[i], arr[largest]); // Recursively heapify the affected sub-tree heapify(arr, n, largest); } } // main function to do heap sort void heapSort(vector &arr, int n) { // Build heap (rearrange array) // We did this from n/2-1 -> 0 b'coz for a complete binary tree last n/2 elements are leave nodes. for (int i = n / 2 - 1; i >= 0; i--) heapify(arr, n, i); // Now arr is a max heap // Pass by ref // One by one extract an element from heap for (int i = n - 1; i > 0; i--) { // Move current root to end swap(arr[0], arr[i]); // call max heapify on the reduced heap heapify(arr, i, 0); } } void print(vector arr){ cout << "Sorted Array is : "; for(int i=0;i arr{10,3,2,5,7}; heapSort(arr,n); print(arr); } ================================================ FILE: Sorting Algorithms/Inbuilt_sorting_algos.cpp ================================================ #include using namespace std; // Keep variables static to avoid some error bool compare(int a, int b){ return a Insertion Sort // 16 < n < 2log(n) --> Quick Sort // 2log(n) < n --> Merge Sort sort(arr,arr+n); // Decreasing sort sort(arr,arr+n,greater<>()); // Alternate and better // sort(arr+n,arr); // Sort using comparator sort(arr,arr+n,compare); // Stable sorting using merge sort // O(n*log^2(n)) if memory is not availabe else O(nlog(n)) stable_sort(arr,arr+n); for(int i=0;i using namespace std; // Merges 2 arrays [lo,mid], [mid+1,hi] void merge(vector &arr,int lo, int hi, int mid){ int i = lo,j = mid+1; vector ans; while(i <= mid or j <= hi){ int l = i > mid ? INT_MAX : arr[i]; // is not in range take INT_MAX int r = j > hi ? INT_MAX : arr[j]; if(l &arr, int lo, int hi) { if(lo>=hi) return; int mid = (lo+hi)/2; mergeSort(arr,lo,mid); mergeSort(arr,mid+1,hi); merge(arr,lo,hi,mid); } void print(vector arr){ cout << "Sorted Array is : "; for(int i=0;i arr = {3,6,1,2,10,7,8,5,9,0}; mergeSort(arr,0,n-1); print(arr); } ================================================ FILE: Sorting Algorithms/O(n^2)_Algos.cpp ================================================ #include using namespace std; // Insertion Sort // We divide an array into 2 parts one is sorted and other is original array // Size of first part keeps on increasing by 1 in each iteration and min value is put there void insertionSort(vector &arr){ int n=arr.size(),i,j; for(i=0;i arr[j] swap them. void selectionSort(vector &arr){ int n=arr.size(),i,j; for(i=0;i arr[j]) swap(arr[i],arr[j]); } // Bubble Sort // Like a bubble move largest element to top // keep on swapping adjacent elements void bubbleSort(vector &arr){ int n = arr.size(),i,j; for(i=0;i arr[j+1]) swap(arr[j],arr[j+1]); } // Stops the comparison when the array is sorted void modified_bubbleSort(vector &arr){ int i,j,n=arr.size(); bool isSorted = false; for(i=0;i arr[j+1]){ isSorted = false; swap(arr[j],arr[j+1]); } } } } void print(vector arr){ cout << "Sorted Array is : "; for(int i=0;i arr = {3,6,1,2,10,7,8,5,9,0}; // bubbleSort(arr); // modified_bubbleSort(arr); insertionSort(arr); // selectionSort(arr); print(arr); } ================================================ FILE: Sorting Algorithms/QuickSort.cpp ================================================ // O(nlog(n)) --> average time Complexcity // O(n^2) --> worst case (If 1st element is chosen as pivot and arr is sorted) // O(1) --> Extra Space // Link --> https://www.hackerearth.com/practice/algorithms/sorting/quick-sort/tutorial/ // Link --> https://www.youtube.com/watch?v=if40LxQ8_Xo&t=1171s #include using namespace std; // All ements to the left of pivot are less than pivot and to the right are greater // It means the element is in its sorted position int partition(vector &arr, int lo, int hi){ int j,i = lo+1; int pivot = arr[lo]; // We try to find index of pivot /* arr[lo] is our pivot Our array lo to hi is divided into 3 regions: [lo+1,j-1] --> Less than Pivot [j,i-1] --> More than Pivot [i,hi] --> Unchecked */ for(j=lo+1;j<=hi;j++){ if(arr[j] < pivot){ swap(arr[i],arr[j]); i++; } } // i-1 is largest index with no. less than pivot // So it is pivot index swap(arr[lo],arr[i-1]); return i-1; } // Divide and Conquer Algo void quickSort(vector &arr, int lo, int hi){ if(lo>=hi) return; int pivot_index = partition(arr,lo,hi); quickSort(arr,lo,pivot_index-1); quickSort(arr,pivot_index+1,hi); } void print(vector arr){ cout << "Sorted Array is : "; for(int i=0;i arr = {3,6,1,2,10,7,8,5,9,0}; quickSort(arr,0,n-1); print(arr); } ================================================ FILE: Sorting Algorithms/RadixSort.cpp ================================================ #include using namespace std; // Time Complexcity = O(d*n) // where d is max no. of digits in a number and n is size of ar // Ref -> https://www.youtube.com/watch?v=a5e7RgCdel0 // Question -> Max Gap Leetcode // We use pegion hole principle + Radix Sort to get ans in O(n) time. // elements inside a bucket = (max_val-min_val)/n-1; // Note bucket index (freq_index here) can be caluclated as (arr[i]-min)/interval void countSort(vector& arr, int exp) { vector freq(10,0); vector ans(arr.size()); for(int i=0;i prefix_index(10,0); for(int i=0;i<10;i++){ prefix_index[i] = freq[i]; if(i != 0) prefix_index[i] += prefix_index[i-1]; } // To convert this prefix arr to index arr // Each value in prefix[i] represnts max index of i for(int i=0;i=0;i--){ int index = (arr[i]/exp)%10; ans[prefix_index[index]] = arr[i]; prefix_index[index]--; } arr = ans; } // Works for +ve elements void radixSort(vector &arr){ int i,max_val = INT_MIN; for(i=0;i arr){ cout << "\nSorted Array is : "; for(int i=0;i arr = {4533,6534,5881,2896,104,7435,8236,7865,909,6450}; radixSort(arr); print(arr); } ================================================ FILE: Sorting Algorithms/cycleSort.cpp ================================================ // Given array of size n has elements from 0 to n-1. // Sorting can be done in O(n) using cycleSort #include using namespace std; void cycleSort(vector& arr, int n) { int i = 0; while(i arr){ cout << "Sorted Array is : "; for(int i=0;i arr{2,3,4,1,0}; cycleSort(arr,n); print(arr); } ================================================ FILE: Strings/KMP.cpp ================================================ // String comapre Algo with O(m+n) m,n being lenghts of string to compare /* * IDEA - Is prefix of pattern again apperaring somewhere again in the pattern. * Ref Link --> https://www.youtube.com/watch?v=V5-7GzOfADQ */ /* * Indices : 0 1 2 3 4 5 6 7 8 9 * Pattern : a b c d a b e a b c * Lps : - - - 1 2 1 2 3 Rest all the values are 0 * Each index in lps represents the index the pointer has to move once once the char in text doesn't match with char in pattern */ #include using namespace std; // pietable // Longest proper Prefix which is also Suffix void computeLPSArray(char* pat, int M, int* lps) { // length of the previous longest prefix suffix int len = 0; lps[0] = 0; // lps[0] is always 0 // the loop calculates lps[i] for i = 1 to M-1 int i = 1; while (i < M) { if (pat[i] == pat[len]) { len++; lps[i] = len; i++; } else // (pat[i] != pat[len]) { // This is tricky. Consider the example. // AAACAAAA and i = 7. The idea is similar // to search step. if (len != 0) { len = lps[len - 1]; // Also, note that we do not increment // i here } else // if (len == 0) { lps[i] = 0; i++; } } } } // Prints occurrences of txt[] in pat[] vector KMPSearch(char* pat, char* txt) { vector ans; int M = strlen(pat); int N = strlen(txt); // create lps[] that will hold the longest prefix suffix // values for pattern int lps[M]; // Preprocess the pattern (calculate lps[] array) computeLPSArray(pat, M, lps); int i = 0; // index for txt[] int j = 0; // index for pat[] while (i < N) { if (pat[j] == txt[i]) { j++; i++; } if (j == M) { ans.push_back(i-j); j = lps[j - 1]; } // mismatch after j matches else if (i < N && pat[j] != txt[i]) { // Do not match lps[0..lps[j-1]] characters, // they will match anyway if (j != 0) j = lps[j - 1]; else i = i + 1; } } return ans; } int main(){ // 0 based indexing char txt[] = "ABABDABACDABABCABAB"; char pat[] = "ABABCABAB"; vector matched_indx = KMPSearch(pat, txt); cout << "pattern appears from following indices: "; for(auto indx : matched_indx) cout << indx << " "; } ================================================ FILE: Strings/PatternMatching.cpp ================================================ // Given a large text and a pattern where text >> pattern. // Find indices for the matching pattern in the text. // Rolling hash method: O(n) time, O(1) space /** * @brief Rolling hash method * hash(pattern) = * hash(pattern[0..m-1]) = (pattern[0]*d^(m-1) + pattern[1]*d^(m-2) + ... + pattern[m-1]) mod q * Also, First character of the pattern is the most significant character hence it's mutiplied by d^(m-1) * * * Formula for Rehashing text in O(1) operation given hash of previous window: * hash( txt[s+1 .. s+m] ) = ( d ( hash( txt[s .. s+m-1]) – txt[s]*h ) + txt[s + m] ) mod q * * NOTE: * d: Number of characters in the alphabet * q: A prime number * h: d^(m-1) mod q */ #include #include #include #include using namespace std; int findModuloPower(int a, int b, int q) { int result = 1; while( b > 0) { if (b & 1) { result = (result * a) % q; } b = b >> 1; a = (a * a) % q; } return result%q; } // Find hash of any string int findStringHash(int d, int h,int q, string str) { int strHash = 0; for (int i = 0; i < str.size(); i++) { strHash = (d * strHash + str[i]) % q; } return strHash; } vector findMatches(string text, string pattern) { int d = 256; // Number of characters in the alphabet int q = 10007; // A prime number int n = text.size(); int m = pattern.size(); int h = findModuloPower(d, m-1, q); // d^(m-1) mod q int patternHash = findStringHash(d, h, q, pattern); int textHash; vector startIndicesOfMatches; for (int i = 0; i <= n - m; i++) { // Don't need to rehash the pattern if(i == 0) textHash = findStringHash(d, h, q, text.substr(0, m)); else // Rehash the text textHash = (d * (textHash - text[i - 1] * h) + text[i + m - 1]) % q; // In case of negative hash, make it positive if (textHash < 0) textHash = textHash + q; if (patternHash == textHash) { bool isMatch = true; // In case of collision, check if the strings are actually equal for (int j = 0; j < m; j++) { if (text[i + j] != pattern[j]) { isMatch = false; break; } } if (isMatch) { startIndicesOfMatches.push_back(i); } } } } int main() { string text = "AABAACAADAABAABA"; string pattern = "AABA"; auto startIndicesOfMatches = findMatches(text, pattern); cout << "Indices of matches: "; for (auto index : startIndicesOfMatches) { cout << index << " "; } } /** * @brief Addition to this problem: * Find number of unique substring in a string * - Get hash for all substrings of length m (O(n*n)) * - Store them in a set and get the size of set * * This method will mostly work as probablity of collision is approx: 1/q ie. 1/10007 = 0.0001% * if we increase q to 10^9 then probablity of collision will be 0.000000001% * * Read more : https://cp-algorithms.com/string/string-hashing.html#determine-the-number-of-different-substrings-in-a-string * * It can be improved by using larger q (10^18) and using a good hash function */ ================================================ FILE: Strings/string_input.cpp ================================================ // If the input format of a string is know... // Ex.str = "233+923i" How to extract numbers #include using namespace std; int main(){ string str = "233+923i"; int a,b; sscanf(str.c_str(), "%d+%di", &a, &b); cout << a << " " << b << endl; //********************************* OR *********************************** str = "I am Nisarg and I love DS-Algo"; vector vec; istringstream iss(str); for(string s;iss >> s;) vec.push_back(s); for(int i=0;ihttps://www.codechef.com/LTIME98B/problems/LGSEG // If an array is to be divided into many segments have a try if binary lifting can help somhow #include const int LIM = (int)2e5+3; using namespace std; // elements of trees are stored from 0 vector tree[LIM]; vector parent(LIM); vector depth(LIM); // up(i,j) stores element 2^j steps above (element)i. int up[LIM][20]; void addEdge(int u, int v) { tree[u].push_back(v); tree[v].push_back(u); } // Precomputes the up using dp. void binary_lifting(int u, int pa) { // up by 2^0 steps up[u][0] = pa; for(int i=1;i<20;i++) { if(up[u][i-1] != -1) up[u][i] = up[ up[u][i-1] ][i-1]; else up[u][i] = -1; } // Vanilla dfs for(auto v: tree[u]) if(v != pa) binary_lifting(v,u); } // returns the node_val at dist h above node // if no node is present returns -1 int getKthAncestor(int node, int h) { // node should not be -1 for(int i=0;i<20 and node != -1;i++) { // if ith bit of h is set if(h & 1<=0;k--) { if(up[a][k] != up[b][k]) { a = up[a][k]; b = up[b][k]; } } // we have reached one level below of LCA return up[a][0]; } int main() { int i,src,u,v,q,x,k,V; cout<<"Enter number of vertices: "; cin>>V; for(i=0;i>u>>v; addEdge(u,v); } src = 0; binary_lifting(src,-1); cout<<"Enter number of queries: "; cin>>q; for(i=0;i> x >> k; cout << "Node :" << getKthAncestor(x,k) << " is at a dist " << k << "from " << x << endl; } } ================================================ FILE: Trees/LCA.cpp ================================================ #include using namespace std; class TreeNode { public: int val; TreeNode *left, *right; }; // Assuming the given 2 nodes always exist TreeNode* LCA_binaryTree(TreeNode* root, int n1, int n2) { if(!root) return NULL; if(root->val == n1 || root->val == n2) return root; TreeNode* left_lca = LCA_binaryTree(root->left,n1,n2); TreeNode* right_lca = LCA_binaryTree(root->right,n1,n2); // if both left and right gives a ptr then root must be LCA if(left_lca and right_lca) return root; // Left must give LCA if(left_lca) return left_lca; else return right_lca; } // For special case of BST TreeNode* LCA_bst(TreeNode* root, int n1, int n2) { if(!root) return NULL; if(n1 < root->val and n2 < root->val) return LCA_bst(root->left,n1,n2); if(n1 > root->val and n2 > root->val) return LCA_bst(root->right,n1,n2); // n1 < root->val and n2 > root->val return root; } // -------------------------------- Helpers --------------------- TreeNode* newNode(int val) { TreeNode* Node = new TreeNode(); Node->val = val; Node->left = Node->right = NULL; return(Node); } int main(){ TreeNode *root = newNode(20); root->left = newNode(8); root->right = newNode(22); root->left->left = newNode(4); root->left->right = newNode(12); root->left->right->left = newNode(10); root->left->right->right = newNode(14); int n1 = 10, n2 = 14; TreeNode *t = LCA_binaryTree(root, n1, n2); cout << "LCA of " << n1 << " and " << n2 << " is " << t->val<val< using namespace std; // Problem Link : https://leetcode.com/problems/word-search-ii/ // Code taken from : https://gist.github.com/SuryaPratapK/6329c354704632725dccc7ec5900d199 class Solution { struct node{ //TrieNode char c; int ends; string word; node *child[26]; }; struct node *getNode(char c) //get newnode { node *newnode = new node; newnode->c = c; newnode->ends = 0; newnode->word = ""; for(int i=0;i<26;++i) newnode->child[i] = NULL; return newnode; } node *root = getNode('/'); //root //Trie INSERT void insert(string s) { node *curr=root; int index,i=0; while(s[i]) { index = s[i]-'a'; if(curr->child[index]==NULL) curr->child[index] = getNode(s[i]); curr=curr->child[index]; i+=1; } curr->ends += 1; curr->word = s; } void solve(vector>& board,int i,int j,int r,int c,vector& ans,node *curr) { //Base case //If the trie doesn't have the current char OR cell is Visited int index = board[i][j]-'a'; if(board[i][j]=='$' || curr->child[index]==NULL) return; curr = curr->child[index]; if(curr->ends > 0) { ans.push_back(curr->word); curr->ends -=1; } //Body char ch = board[i][j]; //Store current char board[i][j] = '$'; //Mark current node visited if(i>0) //TOP solve(board,i-1,j,r,c,ans,curr); if(i0) //LEFT solve(board,i,j-1,r,c,ans,curr); if(j findWords(vector>& board, vector& words) { int r=board.size(); int c=board[0].size(); //Insert all words in TRIE for(int i=0;i ans; for(int i=0;i https://www.geeksforgeeks.org/trie-memory-optimization-using-hash-map/ // NOTE : #include using namespace std; const int LIM = (int)1e7; const int K = (int)(25); typedef struct trie_tag{ bool isEnd; map mp; trie_tag(){isEnd = false;} }trie; // Global delecration of root pointing to null trie * root = NULL; void insert(string str) { if(root == NULL) root = new trie; trie* curr = root; for(char ch : str) { if(curr -> mp.find(ch) == curr -> mp.end()) curr -> mp[ch] = new trie; // As we want to move inside that part of trie curr = curr -> mp[ch]; } curr -> isEnd = true; } bool search(string str) { trie *curr = root; if(curr == NULL) return false; for(char ch : str) { if(!curr -> mp[ch]) return false; // As we want to move inside that part of trie curr = curr -> mp[ch]; } return curr -> isEnd; } // bool delete(string str) // { // return 0; // } int main(void) { vector arr = {"AABAC","AAB","ABC","AEFDH","BCD"}; for(auto it: arr) insert(it); if(search("AEFD")) cout << "PRESENT\n"; else cout << "ABSENT\n"; } ================================================ FILE: codesnippet.cpp ================================================ // Nisarg Gogate // VNIT #include #define DEBUG_ON 0 #define int long long #define TESTCASES false #define FASTIO true #define DBG(x) if(DEBUG_ON) cout << #x << " == " << x << endl #define FF first #define SS second const int inf = (int)1e18 + 1; const int SIZE = (int)1e5+3; const int MOD = (int)1e9+7; using namespace std; int exp(int x,int n) { int ret= 1; while(n>0) { if(n%2)ret=(ret*x)%MOD; x=(x*x)%MOD; n=n/2; } return ret%MOD; } int inv(int x) { return exp(x,MOD-2); } int ncr(int n,int r) { if(r==0)return 1; if(n arr(n,0); for (auto &it : arr) cin >> it; } void main_code() { int i,j,n,k; cin>>n; cout<> T; while(T--) main_code(); }