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 <bits/stdc++.h>
using namespace std;
int findRandom(vector<int> 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<int>& 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<int> 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<bits/stdc++.h>
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<int> 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<sqrt(LIM);i++)
{
if(isComposite[i]) continue;
for(int j=2*i; j<LIM; j += i) //move by i steps at once
{
isComposite[j]=true;
if(factor[j] == 0) factor[j]=i;
}
}
for(i=3;i<LIM;i+=2)
{
if(!isComposite[i]) primes.push_back(i);
}
//Q1
int n;
cout<<"Enter number you want to check to be prime:";
cin>>n;
cout<<!isComposite[n]<<endl;
//Q2
int F;
cout<<"Enter Number you want to factorize: ";
cin>>F;
while (isComposite[F] and F!=1)
{
cout<<factor[F]<<" "; //F = a * b if a is a prime which is stored.
F=F/factor[F];
}
cout<<F<<endl; //final prime number.
//Q3
int a,b;
cout<<"Enter range you want to check: ";
cin>>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<int>& 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<bits/stdc++.h>
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 " <<getMostWork_method1(arr,4,n) << "\n";
cout << "Minimum possible maximum folders per person " <<getMostWork_method2(arr,4,n);
}
================================================
FILE: Adhoc + Basic/binary_search_II.cpp
================================================
// Reference --> 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<bits/stdc++.h>
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<int> arr, int target){
int lo = 0;
int hi = arr.size()-1;
while(lo<hi){
int mid = (lo+hi)/2;
if(arr[mid] < target)
lo = mid+1;
else if(arr[mid] > 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<int> arr, int target){
int lo = 0;
int hi = arr.size()-1;
while(lo<hi){
int mid = lo+(hi-lo+1)/2; // Note from observation above
if(arr[mid] < target)
lo = mid+1;
else if(arr[mid] > 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<int> &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<int> &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<int> :: 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<int> 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<bits/stdc++.h>
using namespace std;
int lowerBound(vector<int> 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<int> 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<INT_MAx (why not compare 2 and 6? they are from same array so they will be already in sorted order no need to check that)
In general
. . . leftx | rightx . . .
. . . lefty | righty . . .
leftx<=righty && lefty<=rightx for valid configuration
Now if we find a point in first array, we can get all others since we divide into halves (refer code)
so find this point using binary search
*/
#include<bits/stdc++.h>
using namespace std;
class Solution {
public:
double findMedian(vector<int>&a,vector<int>&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<int>& nums1, vector<int>& nums2) {
if(nums1.size()<nums2.size())
{
return findMedian(nums1,nums2);
}
else
{
return findMedian(nums2,nums1);
}
}
};
================================================
FILE: Arrays/MedianOfStream.cpp
================================================
/*
Time complexity: O(N*(log(N)))
Space complexity: O(N)
where N is the total number of elements in the array.
*/
#include<bits/stdc++.h>
using namespace std;
vector<int> findMedian(vector<int> &arr, int n){
// To store the medians
vector<int> medians;
// max heap
priority_queue<int> lo;
//min heap
priority_queue<int, vector<int>, greater<int>> 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<bits/stdc++.h>
using namespace std;
vector<int> nextGreaterElement(vector<int> arr) {
stack<pair<int,int> > stck;
int i,n = arr.size();
vector<int> ans(n);
for(i=0;i<n;i++) { // Can be written as n->1
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<int> nextSmallerElement(vector<int> arr) {
stack<int> stck;
int i,n = arr.size();
vector<int> ans(n, -1);
for(i=0;i<n;i++) {
while(!stck.empty() and arr[i] < arr[stck.top()]) {
ans[stck.top()] = arr[i];
stck.pop();
}
stck.push(i);
}
return ans;
}
int main() {
vector<int> arr = {1, 7, 2, 3, 1, 8};
vector<int> nextGreater = nextGreaterElement(arr);
cout << "\nNext Greater Element: ";
for (auto ele: nextGreater)
cout << ele << " ";
vector<int> 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<bits/stdc++.h>
using namespace std;
class Solution {
public:
int trap(vector<int>& 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 multiplying x with 2^y
// right shifting (x>>y) is equivalent to dividing x with 2^y.
#include<bits/stdc++.h>
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<<i&subset)
cout << i+1<<" ";
}
cout<<"\n";
}
int main()
{
// num represents subset of numbers from 1 to 10
int num = 15;
display(num);
// delete the d from subset num
int d = 4;
erase_or_add(d,num);
display(num);
d=9;
erase_or_add(d,num);
display(num);
}
================================================
FILE: DP/LCS.cpp
================================================
/**
* @file LCS.cpp
* @author Nisarg
* @brief Longest comman Subsequence in given two strings
* NOT HERE APPLICABLE: // By iterating in reverse order in the inner loop. we can further optmized on space to use single dp array/
* ex. Soln 4: https://leetcode.com/problems/partition-equal-subset-sum/editorial/
*
*/
#include<bits/stdc++.h>
using namespace std;
void LCS(string a, string b) {
int n = a.size(), m = b.size();
vector<vector<int> > dp(n+1, vector<int> (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<int> dp(m+1, 0);
vector<int> 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<bits/stdc++.h>
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<int> 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<int> arr) {
int n = arr.size();
vector<int> dp(n, 1); // dp[i] = 1 as LIS can be itself
for(int i=0; i<n; i++) {
for (int j=0; j<i; j++) {
if(arr[j] < arr[i] )
dp[i] = max(dp[i], arr[j]+1);
}
}
return dp[n-1];
}
// We can get exact LIS by using parent array.
void find_LIS(int arr[], int n) {
vector<int> 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<int> aux(n, 0);
vector<vector<int>> 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<M<N<10^5
// Find minimum elements you need to add in arr1 such that arr2 is a subsequence of arr1?
// Soln: Codenation 1 april 2020 : hint(use maps, LIS)
================================================
FILE: DP/LongestPalindromicSubstring.cpp
================================================
#include<bits/stdc++.h>
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<n;gap++) // gap betn 1st and last element of substring
{
for(int i=0,j=gap ; j<n ; i++,j++)
{
if(gap==0)
{
dp[i][j] = true;
}
else if(gap==1)
{
dp[i][j] = (s[i]==s[j]);
}
else
{
dp[i][j] = (s[i]==s[j] && dp[i+1][j-1]);
}
if(dp[i][j])
{
start = i;
end = j;
}
}
}
return s.substr(start,end-start+1);
}
};
/*
* Alternte Soln can be made from observation that palindrome has same elements from center.
* So choose center and find left of center and right of center as 2 pointers compare and get length.
* Optimization - if(isPalindrome(i,j)) is true and S[i-1] == S[j+1] then isPalindrome(i-1,j+!1) is also true.
* This operation is to be done for odd as well as even. O(n) Time and O(1) Space.
*/
================================================
FILE: DP/LongestPanlidromicSubsequence.cpp
================================================
/**
* @file LongestPanlidromicSubsequence.cpp
* @author Nisarg Gogate
* @brief Find Longest palindrome subsequence
* Or Find k -palindrome. Remove at max k characters such that the string formed is a palindrome.
*/
#include <bits/stdc++.h>
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<vector<int> > dp(n + 1, vector<int>(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<vector<int> > dp(n + 1, vector<int>(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<int> 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 <bits/stdc++.h>
using namespace std;
int SIZE = 2002;
vector<vector<int>> dp(SIZE, vector<int>(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<int> dp(n, 0);
vector<vector<bool>> isPalindrome(n, vector<bool>(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<int> 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<bits/stdc++.h>
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<<digit_dp(R,R.size(),x,1);
}
================================================
FILE: DP/travelling_salesman_prob.cpp
================================================
// Reference -> 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<bits/stdc++.h>
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<<n) -1;
int dp[16][4];
int TSP(int visited,int position)
{
// Initially checking whether all the places are visited or not
if(visited==all_visited)
return distan[position][0];
if(dp[visited][position]!=-1)
return dp[visited][position];
// init
int answer = MAX;
// chack for each city
for(int city=0;city<n;city++)
if((visited&(1<<city))==0) // is the city visited check
answer = min(answer, distan[position][city] + TSP( visited|(1<<city),city));
return dp[visited][position] = answer;
}
int main()
{
memset(dp,-1,sizeof dp);
cout<<"Minimum Distance Travelled by traveller is "<<TSP(1,0);
return 0;
}
================================================
FILE: Geometry/anglecoverted.cpp
================================================
// given question : https://leetcode.com/discuss/interview-question/5567668/Google-Interview-Onsite-1
================================================
FILE: Graph/BFS.cpp
================================================
#include<bits/stdc++.h>
// 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<int> adj[LIM];
// vector<int> dist(LIM,-1);
// vector<int> 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<int> 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<<u<<" ";
for(int v : adj[u])
{
if(!visited[v])
{
// dist[v] = dist[u] + 1;
// parent[v] = u;
visited[v]=true; //NOTE : We put visited here inside the inner loop
q.push(v);
}
}
}
}
int main()
{
int V,i,src,u,v,wt,E;
cout<<"Enter number of vertices and edges: ";
cin>>V>>E;
for(i=0;i<E;i++)
{
cout<<i+1<<". Enter vertex name u and v: ";
cin>>u>>v;
addEdge(u,v);
}
cout<<"Enter source node for iterative bfs: ";
cin>>src;
cout<<"BFS=> ";
bfs(src);
cout<<endl;
}
================================================
FILE: Graph/Bellman_ford(Negative_weights).cpp
================================================
/*
Reference -> 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<bits/stdc++.h>
#define LIM 3000
#define INF 1e5+3
using namespace std;
//NOTE: Here reprentation of graph is done a bit differnetly
typedef pair<int,int> pii;
vector<vector<int>> G(LIM,vector<int>(3));
vector<int> 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<V-1;k++)
{
for(auto itr : G)
{
int u = itr[0];
int v = itr[1];
int wt = itr[2];
min_dist[v] = min(min_dist[v],min_dist[u]+wt);
}
}
// If the min min_dist is still changing even after V-1 iterstions means there is no soln.
for(auto itr : G)
{
int u = itr[0];
int v = itr[1];
int wt = itr[2];
if(min_dist[v] > 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<<endl;
for(i=0;i<8;i++)
{
cout<<"Enter vertex name u , v and weight: ";
cin>>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<<endl;
cout<<"Min distace all nodes from "<<src<<"is:\n";
for(int i=0;i<V;i++)
cout<<i<<" : "<<min_dist[i]<<endl;
}
================================================
FILE: Graph/Bipartite_Coloring.cpp
================================================
#include<bits/stdc++.h>
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<int> adj[LIM];
vector<col> color(LIM,WHITE);
void addEdge(int u, int v)
{
adj[u].push_back(v);
adj[v].push_back(u);
}
void bfs()
{
queue<int> q;
int d=0;
for(int i=1;i<LIM;i++)
{
// if we find a new part of G
if(color[i] == WHITE)
q.push(i);
while(!q.empty())
{
int u = q.front();
q.pop();
// If no color is given give a random color
if(color[u] == WHITE)
color[u] = GREY;
for(int v : adj[u])
{
if(color[v] == WHITE)
{
if(color[u] == GREY)
color[v] = BLACK;
else
color[v] = GREY;
q.push(v);
}
else
{
// If adjecent nodes have same color
if(color[u] == color[v])
{
cout << "IMPOSSIBLE";
return;
}
}
}
}
}
cout << "Color for ith node is: " << endl;
for(int i=1;i<LIM;i++)
{
cout << i<< " " <<color[i];
}
}
int main()
{
int V,i,src,u,v,wt,E;
cout<<"Enter number of vertices and edges: ";
cin>>V>>E;
for(i=0;i<E;i++)
{
cout<<i+1<<". Enter vertex name u and v: ";
cin>>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 <bits/stdc++.h>
using namespace std;
int jobs = 6, applicants = 6;
vector<vector<int> > G;
vector<int> currentMatching(jobs, -1); // Job i mapped with currentMatching[i] applicant.
vector<bool> 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<bits/stdc++.h>
#define LIM 3000
#define INF 1e5+3
using namespace std;
vector<int> 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<int> stck;
stck.push(src);
while(stck.size())
{
int u=stck.top();
stck.pop();
visited[u]=true;
cout<<u<<" ";
for(auto v:adj[u])
{
if(!visited[v])
stck.push(v);
}
}
memset(visited,0,sizeof(visited));
}
void dfs_recursive(int u)
{
if(visited[u])
return ;
visited[u]=true;
cout<<u<<" ";
for(int v : adj[u])
{
if(!visited[v])
dfs_recursive(v);
}
}
int main()
{
int V,i,src,u,v,wt;
cout<<"Enter number of vertices and edges: ";
cin>>V>>E;
for(i=0;i<E;i++)
{
cout<<i+1<<". Enter vertex name u and v: ";
cin>>u>>v;
addEdge(u,v);
}
cout<<"Enter source node for iterative dfs: ";
cin>>src;
cout<<"Iterative_DFS=> ";
dfs_iterative(0);
cout<<endl;
cout<<"Enter source node for recursive dfs: ";
cin>>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<bits/stdc++.h>
using namespace std;
void findShortestDist(vector<vector<int>>& 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<vector<int> > matrix(V, vector<int>(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<bits/stdc++.h>
#define LIM 1007
using namespace std;
vector<int> G[LIM];
// Other way of doing this is by bipartiate coloring
bool isCyclicInDirectedGraph(int n, vector<int> inDegree) {
int i;
queue<int> q; // NOTE: it stores the topo sorted order
for(i=0;i<inDegree.size();i++)
if(inDegree[i] == 0)
q.push(i);
while(!q.empty()) {
int u = q.front();
q.pop();
for(auto v : G[u]) {
inDegree[v]--;
if(inDegree[v] == 0)
q.push(v);
}
}
// Nodes with more than 1 in degree must be in cycle so they were never inserted in queue.
for(i=0;i<n;i++)
if(inDegree[i]!= 0)
return true;
return false;
}
int main() {
int n, edges, u, v;
cout << "Enter the number of vertices and edges: ";
cin >> n >> edges;
vector<int> inDegree(n);
for(int i=0;i<edges;i++) {
cin >> 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<bits/stdc++.h>
#define LIM 3000
#define INF 1e5+3
typedef pair<int,int> pii;
using namespace std;
//NOTE: Global variables are initailized to 0
vector<pii> adj[LIM];
vector<int> 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<pii, vector<pii>, greater<pii> > pq;
for(int i=0;i<LIM;i++)
min_dist[i]=INF; //Init to infinity
min_dist[src]=0;
pq.push({0,src});
while(pq.size())
{
int curr = pq.top().second;
pq.pop();
// Optimized to not traverse children if minDist which was encountered earlier was better
// This helps avoid traversing children if we already have a miniDist smaller traversed earlier
if( curr > 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<<endl;
for(i=0;i<E;i++)
{
cout<<"Enter vertex name u , v and weight: ";
cin>>u>>v>>wt;
addEdge(u,v,wt);
}
cout<<"Enter the source node: ";
cin>>src;
dijktra(src);
cout<<endl;
cout<<"Min distace all nodes from "<<src<<"is:\n";
for(int i=0;i<V;i++)
cout<<i<<"-"<<min_dist[i]<<endl;
}
================================================
FILE: Graph/prims_algo.cpp
================================================
/*
Minimum Spanning tree is (minimum sum) tree with V-1 edges
Total sum of all the edges must be minimum in O(ElnV)
E-Edges V-Vertices
NOTE : We can't find minimal spanning tree using distra's algo
2
O-------A
10 / \ 11
/ \
B-----C
2
Using dijstar's if we start from O we will have edges O-A,A-B,A-C
as from O-B dist = 12/15 and O-C distance = 14/13
*/
#include<bits/stdc++.h>
#define LIM 3000
#define INF 1e5+3
using namespace std;
typedef pair<int, int> pii;
vector<pii> 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<pii, vector<pii>, greater<pii> > 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<<endl;
for(i=0;i<E;i++)
{
cout<<"Enter vertex name u , v and weight: ";
cin>>u>>v>>wt;
addEdge(u,v,wt);
}
cout<<"Minimum spanning tree sum: ";
cout<<prim()<<endl;
}
================================================
FILE: Graph/topological_sort.cpp
================================================
// Not necessarily unique
// Acyclic graph and directed graph
/*
Que -> 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<bits/stdc++.h>
#define LIM 3000
#define INF 1e5+3
typedef enum {WHITE,GREY,BLACK} col; //white-no col
using namespace std;
int V,E;
vector<int> G[LIM];
vector<bool> visited(LIM,false);
vector<col> 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<int>& 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<E;i++)
{
int u,v;
cin >> 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<int> 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 <bits/stdc++.h>
using namespace std;
vector<int> parent; // Keeps track of group representative/parent
vector<int> 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<int> arr, int k){
set<int> s;
int sum=0;
for(int i=0;i<arr.size();i++){
sum += arr[i];
int val = sum%k==0?k:sum%k;
if(s.find(val) == s.end())
s.insert(val);
else
return false;
}
return true;
}
================================================
FILE: Greedy or DP (Problems)/Job_scheduling.cpp
================================================
// Link --> 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<int>& startTime, vector<int>& endTime, vector<int>& profit) {
int n = startTime.size();
vector<vector<int>> 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<int, int> 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<int> arr) {
int n = arr.size(),i,ans_sum=0,curr_sum = arr[0];
for(i=1;i<n;i++){
curr_sum = max(arr[i],curr_sum+arr[i]);
ans_sum = max(ans_sum,curr_sum);
}
return ans_sum;
}
// Find maximum product of subarray
// https://leetcode.com/problems/maximum-product-subarray/
int maxProductSubarray(vector<int> arr) {
int ans = arr[0],max_val=arr[0],min_val=arr[0];
for(int i=1;i<arr.size();i++) {
if(arr[i] < 0)
swap(max_val,min_val);
max_val = max(arr[i],max_val*arr[i]);
min_val = min(arr[i],min_val*arr[i]);
ans = max(ans,max_val);
}
return ans;
}
// In such formula based question try to break down the formula
// Find max value of arr[i]+arr[j]+i-j where i<j
// https://leetcode.com/problems/best-sightseeing-pair/
int max_pair(vector<int> 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<n;i++){
ans = max(ans,prev_max+arr[i]-i);
prev_max = max(prev_max,arr[i]+i);
}
return ans;
}
================================================
FILE: Greedy or DP (Problems)/Queue_Reconstruction.cpp
================================================
/*Given n peps with [hi,ki] where ki denotes number of peps with height
* greater than or eqaul to hi to its left in final queue
* https://leetcode.com/problems/queue-reconstruction-by-height/
* Soln -> Time Complexcity O(n logn)
*/
#include<bits/stdc++.h>
using namespace std;
// Return The sequence which satisfies the given condition
vector<pair<int,int>> queue_reconstruction(vector<pair<int,int>> 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<int,int> p1,pair<int,int> p2){
return p1.first>p2.first or
(p1.first == p2.first and p1.second<p2.second);
});
// can be written as compare function as well
vector<pair<int,int>> ans;
for(int i=0;i<people.size();i++)
// We have to insert the person into people[i].second position
// as all the k persons before that index are greater than or equal in height as person[i]
ans.insert(ans.begin()+people[i].first,people[i]);
// Insert function takes in 2 param - position (iterator) - value
}
================================================
FILE: Greedy or DP (Problems)/jump_problem.cpp
================================================
// Link : https://leetcode.com/problems/jump-game-ii/
// Reach from 0th index to nth index with minimum number of jumps
// arr[i] represents max jump possible from ith index.
#include<bits/stdc++.h>
using namespace std;
int min_jump(vector<int> 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-1;i++)
{
max_reachable_index = max(arr[i]+i,max_reachable_index);
// we can't go anyfurther without doing an extra jump
if(i == range_of_jump)
{
range_of_jump = max_reachable_index;
jump++;
}
}
return jump;
}
signed main()
{
int n;
cin >> n;
vector<int> 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<bits/stdc++.h>
using namespace std;
class Solution {
public:
vector<int> prefix;
Solution(vector<int>& w) {
prefix.push_back(w[0]);
for(int i=1;i<w.size();i++) {
prefix.push_back(prefix.back()+w[i]);
}
}
int pickIndex() {
float fraction = (float)rand()/RAND_MAX;
int num = fraction*prefix.back();
auto it = lower_bound(prefix.begin(), prefix.end(), num*prefix.back());
return it-prefix.begin();
}
};
================================================
FILE: OS Concept based algos/LRU-Cache.cpp
================================================
// We can use stl container list as a double
// ended queue to store the cache keys, with
// the descending time of reference from front
// to back and a set container to check presence
// of a key. But to fetch the address of the key
// in the list using find(), it takes O(N) time.
// This can be optimized by storing a reference
// (iterator) to each key in a hash map.
// Refer : https : // leetcode.com/problems/lru-cache/ my solutions
#include <bits/stdc++.h>
using namespace std;
class LRUCache
{
int capacity;
list<pair<int, int>> dq; // key, value pair
// store references of key in cache
unordered_map<int, list<pair<int, int>>::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<int, int> 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<bits/stdc++.h>
using namespace std;
const int LIM = 1e3;
vector<int> 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;i<n;i++)
difference[i] = arr[i]-arr[i-1];
}
// add x to all elements in between l and r (inclusive) in O(1)
void update_range(int arr[], int l, int r, int n, int x)
{
// invalid ip
if(l<0 or r >n-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<n;i++)
arr[i] = arr[i-1] + difference[i];
for(int i=0;i<n;i++)
cout<<arr[i]<<" ";
}
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);
int l=7,r=12;
// Add 5 to all elements in range l to r
update_range(arr,l,r,n,5);
print(arr,n);
}
================================================
FILE: Range_queries/Segment_trees.cpp
================================================
//Segment tree for sum range-queries and updation
/*
one-based indexing
LIM=N
1. Initialization -> 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<bits/stdc++.h>
#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(b<node_lower or a>node_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(b<node_lower or a>node_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<<range_query(1,a,b,1,10)<<endl;
//Update query[a,b] with +val
cout<<"Update: Enter range a,b : ";
cin>>a>>b;
cout<<endl<<"Update: Enter val : ";
cin>>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<<range_query(1,a,b,1,10)<<endl;
}
================================================
FILE: Range_queries/sparce_table.cpp
================================================
// Reference -> 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<bits/stdc++.h>
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<<i) <= r-l+1)
{
ans = min(ans,st[l][i]);
l += 1<<i;
}
}
return ans;
}
// We are taking advantage that we don't need to keep intervals disjoint. (Intervals me overlap)
// we can split the range [1,6] into the ranges [1,4] and [3,6]
// Both in power of 2 (we used data from [3,4] again) So must be idempotent
int query_idempotent(int l, int r)
{
// j denotes the lenth of interval
int j = log2(r-l+1);
// r - 2^j + 1 the start indx of next range of length j.
return f(st[l][j], st[r-(1<<j)+1][j]);;
}
int main(void)
{
int arr[15] = { 568, 712, 412, 231, 241, 393, 865, 287, 128, 457, 238, 98, 980, 23, 782 };
int n = sizeof(arr)/sizeof(int);
init(arr,n);
cout<<"Minimum number in O(NLogN) in range: "<<query_normal(2,3)<<endl;
cout<<"Minimum number in O(1) in range: "<<query_idempotent(2,3)<<endl;
return 0;
}
================================================
FILE: Range_queries/sqrt_decomposition.cpp
================================================
================================================
FILE: Range_queries/which_to_use_when.txt
================================================
If we need to make range update Seg_tree will most likely work
================================================
FILE: Sorting Algorithms/HeapSort.cpp
================================================
// Given an array implementation of Complete Binary Tree
// Heapify function takes O(logn)
// n is the size of array.
#include<bits/stdc++.h>
using namespace std;
// Generates heap from ith node and it's children.
void heapify(vector<int> &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<int> &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<int> arr){
cout << "Sorted Array is : ";
for(int i=0;i<arr.size();i++)
cout << arr[i] <<" ";
cout << endl;
}
int main(){
int n = 5;
vector<int> arr{10,3,2,5,7};
heapSort(arr,n);
print(arr);
}
================================================
FILE: Sorting Algorithms/Inbuilt_sorting_algos.cpp
================================================
#include<bits/stdc++.h>
using namespace std;
// Keep variables static to avoid some error
bool compare(int a, int b){
return a<b; // Just write down the condn you want to satisfy
}
int main(){
int n = 5;
int arr[n] = {10,3,2,5,7};
// Uses Intro sort
// n < 16 --> 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<n;i++)
cout << arr[i] << " ";
}
================================================
FILE: Sorting Algorithms/MergeSort.cpp
================================================
// Merge Sort O(nlog(n)) with O(n) space
// else O(nlog^2(n)) with O(1) space
#include<bits/stdc++.h>
using namespace std;
// Merges 2 arrays [lo,mid], [mid+1,hi]
void merge(vector<int> &arr,int lo, int hi, int mid){
int i = lo,j = mid+1;
vector<int> 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<r)
ans.push_back(l),i++;
else
ans.push_back(r),j++;
}
for(i=0;i<ans.size();i++)
arr[lo+i] = ans[i];
}
// We merge sorted array so call Merge Sort first then merge
void mergeSort(vector<int> &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<int> arr){
cout << "Sorted Array is : ";
for(int i=0;i<arr.size();i++)
cout << arr[i] <<" ";
cout << endl;
}
int main(){
int n = 10,i;
vector<int> 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<bits/stdc++.h>
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<int> &arr){
int n=arr.size(),i,j;
for(i=0;i<n;i++){
int min_val = arr[i];
int min_val_indx = i;
for(j=i+1;j<n;j++){
if(arr[j] < min_val){
min_val = arr[j];
min_val_indx = j;
}
}
swap(arr[i],arr[min_val_indx]);
}
}
// Selection Sort
// Select 2 indices i,j where i<j.
// If arr[i] > arr[j] swap them.
void selectionSort(vector<int> &arr){
int n=arr.size(),i,j;
for(i=0;i<n;i++)
for(j=i+1;j<n;j++)
if(arr[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<int> &arr){
int n = arr.size(),i,j;
for(i=0;i<n;i++)
for(j=0;j<n-i-1;j++)
if(arr[j] > arr[j+1])
swap(arr[j],arr[j+1]);
}
// Stops the comparison when the array is sorted
void modified_bubbleSort(vector<int> &arr){
int i,j,n=arr.size();
bool isSorted = false;
for(i=0;i<n and !isSorted;i++){
isSorted = true;
for(j=0;j<n-i-1;j++){
if(arr[j] > arr[j+1]){
isSorted = false;
swap(arr[j],arr[j+1]);
}
}
}
}
void print(vector<int> arr){
cout << "Sorted Array is : ";
for(int i=0;i<arr.size();i++)
cout << arr[i] <<" ";
cout << endl;
}
int main(){
int n = 10,i;
vector<int> 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<bits/stdc++.h>
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<int> &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<int> &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<int> arr){
cout << "Sorted Array is : ";
for(int i=0;i<arr.size();i++)
cout << arr[i] <<" ";
cout << endl;
}
int main(){
int n = 10;
vector<int> arr = {3,6,1,2,10,7,8,5,9,0};
quickSort(arr,0,n-1);
print(arr);
}
================================================
FILE: Sorting Algorithms/RadixSort.cpp
================================================
#include<bits/stdc++.h>
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<int>& arr, int exp) {
vector<int> freq(10,0);
vector<int> ans(arr.size());
for(int i=0;i<arr.size();i++)
freq[(arr[i]/exp) %10]++; // arr[i]/100 %10 gives ele at 1000th place
vector<int> 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<freq.size();i++)
prefix_index[i]--;
// We traverse in reverse as we want to keep Radix sort stable
for(int i=arr.size()-1;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<int> &arr){
int i,max_val = INT_MIN;
for(i=0;i<arr.size();i++)
max_val = max(max_val,arr[i]);
int exp = 1;
// Loop till the msb of max_val
while(exp <= max_val) {
// apply count sort on (exp)'s place
countSort(arr,exp);
exp *= 10;
}
}
void print(vector<int> arr){
cout << "\nSorted Array is : ";
for(int i=0;i<arr.size();i++)
cout << arr[i] <<" ";
cout << endl;
}
int main(){
int n = 10;
vector<int> 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<bits/stdc++.h>
using namespace std;
void cycleSort(vector<int>& arr, int n) {
int i = 0;
while(i<n) {
if(arr[i] != arr[arr[i]])
swap(arr[i], arr[arr[i]]);
else
i++; // Move to next ele after the element in ith index is i
}
}
void print(vector<int> arr){
cout << "Sorted Array is : ";
for(int i=0;i<arr.size();i++)
cout << arr[i] <<" ";
cout << endl;
}
int main(){
int n = 5;
vector<int> 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<bits/stdc++.h>
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<int> KMPSearch(char* pat, char* txt)
{
vector<int> 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<int> 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 <iostream>
#include <vector>
#include <string>
#include <cmath>
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<int> 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<int> 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<bits/stdc++.h>
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<string> vec;
istringstream iss(str);
for(string s;iss >> s;)
vec.push_back(s);
for(int i=0;i<vec.size();i++)
cout << vec[i] << endl;
//************************* String with spaces input ********************
// string input;
// cin.ignore();
// getline(cin, input, '\n');
}
================================================
FILE: Trees/Binary_Lifting.cpp
================================================
// Note : Is apllicable only on trees
// Precomutation : NLog(N)
// Query output (to find LCA as well as kth ancestor) : Log(N)
// N is basically the max height possible
// Q. Find element kth place above x.
// Can also be used to find LCA(Lowest Comman Ancestor) for a,b:
// Demo que -->https://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<bits/stdc++.h>
const int LIM = (int)2e5+3;
using namespace std;
// elements of trees are stored from 0
vector<int> tree[LIM];
vector<int> parent(LIM);
vector<int> 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<<i)
node = up[node][i];
}
return node;
}
// returns Lowest common Ancestor for nodes a,b
int LCA(int a, int b)
{
if(depth[a] < depth[b])
swap(a,b);
int diff = depth[a] - depth[b];
// move a diff levels up till both a and b are not on same level
a = getKthAncestor(a,diff);
// imp condition
if(a == b)
return a;
// move up by 2^k steps only if on moving 2^k steps up a is not equals b.
for(k=19;k>=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<V-1;i++)
{
cout<<i+1<<". Enter vertex name u and v: ";
cin>>u>>v;
addEdge(u,v);
}
src = 0;
binary_lifting(src,-1);
cout<<"Enter number of queries: ";
cin>>q;
for(i=0;i<q;i++)
{
cin >> x >> k;
cout << "Node :" << getKthAncestor(x,k) << " is at a dist "
<< k << "from " << x << endl;
}
}
================================================
FILE: Trees/LCA.cpp
================================================
#include<bits/stdc++.h>
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<<endl;
t = LCA_bst(root, n1, n2);
cout << "LCA of " << n1 << " and " << n2 << " is " << t->val<<endl;
}
================================================
FILE: Trees/WordSearch2.cpp
================================================
#include<bits/stdc++.h>
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<vector<char>>& board,int i,int j,int r,int c,vector<string>& 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(i<r-1) //DOWN
solve(board,i+1,j,r,c,ans,curr);
if(j>0) //LEFT
solve(board,i,j-1,r,c,ans,curr);
if(j<c-1) //RIGHT
solve(board,i,j+1,r,c,ans,curr);
board[i][j] = ch; //Mark current node as Unvisited by restoring the value
}
public:
vector<string> findWords(vector<vector<char>>& board, vector<string>& words) {
int r=board.size();
int c=board[0].size();
//Insert all words in TRIE
for(int i=0;i<words.size();++i)
insert(words[i]);
//Now search words
vector<string> ans;
for(int i=0;i<r;++i)
{
for(int j=0;j<c;++j)
solve(board,i,j,r,c,ans,root);
}
return ans;
}
};
================================================
FILE: Trees/trie.cpp
================================================
// Reference -> https://www.geeksforgeeks.org/trie-memory-optimization-using-hash-map/
// NOTE :
#include<bits/stdc++.h>
using namespace std;
const int LIM = (int)1e7;
const int K = (int)(25);
typedef struct trie_tag{
bool isEnd;
map<char,trie_tag*> 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<string> 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<bits/stdc++.h>
#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<r)return 0;
int ret = n*ncr(n-1,r-1);
ret%=MOD;
ret*=inv(r);
ret%=MOD;
return ret;
}
int solve(int n)
{
int i,j,ans=0;
vector<int> arr(n,0);
for (auto &it : arr) cin >> it;
}
void main_code()
{
int i,j,n,k;
cin>>n;
cout<<solve(n)<<endl;
}
signed main()
{
// freopen("input.txt", "r", stdin);
// freopen("output.txt", "w", stdout);
if(FASTIO)
{
ios_base::sync_with_stdio(false);
cin.tie(NULL);
}
int T = 1;
if(TESTCASES)
cin >> T;
while(T--)
main_code();
}
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
SYMBOL INDEX (173 symbols across 54 files)
FILE: Adhoc + Basic/Reservoir_sampling.cpp
function findRandom (line 16) | int findRandom(vector<int> arr)
function weightedRandomIndex (line 39) | int weightedRandomIndex(const std::vector<int>& weights) {
function main (line 54) | int main()
FILE: Adhoc + Basic/Sieve_of_Eratosthenes.cpp
function main (line 18) | int main()
FILE: Adhoc + Basic/Two_Pointer.cpp
function sortColors (line 11) | void sortColors(vector<int>& arr) {
FILE: Adhoc + Basic/binary_search_I.cpp
function getMostWork_method1 (line 12) | int getMostWork_method1(int folders[], int workers,int n)
function ispossible (line 43) | bool ispossible(int folders[],int n, int no, int workers)
function getMostWork_method2 (line 61) | int getMostWork_method2(int folders[],int workers, int n)
function main (line 85) | int main()
FILE: Adhoc + Basic/binary_search_II.cpp
function lower_bound_ (line 32) | int lower_bound_(vector<int> arr, int target){
function upper_bound_ (line 50) | int upper_bound_(vector<int> arr, int target){
function find_pivot (line 80) | int find_pivot(vector<int> &arr) {
function pivotedBinarySearch (line 103) | int pivotedBinarySearch(vector<int> &arr, int target){
function main (line 123) | int main(){
FILE: Adhoc + Basic/binary_search_III.cpp
function lowerBound (line 5) | int lowerBound(vector<int> arr, int target) {
function upperBound (line 23) | int upperBound(vector<int> arr, int target) {
FILE: Arrays/MedianOfSortedArrays.cpp
class Solution (line 34) | class Solution {
method findMedian (line 36) | double findMedian(vector<int>&a,vector<int>&b){
method findMedianSortedArrays (line 59) | double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
FILE: Arrays/MedianOfStream.cpp
function findMedian (line 13) | vector<int> findMedian(vector<int> &arr, int n){
FILE: Arrays/MonotonicStack.cpp
function nextGreaterElement (line 15) | vector<int> nextGreaterElement(vector<int> arr) {
function nextSmallerElement (line 39) | vector<int> nextSmallerElement(vector<int> arr) {
function main (line 54) | int main() {
FILE: Arrays/TrappingRainwater.cpp
class Solution (line 4) | class Solution {
method trap (line 6) | int trap(vector<int>& height) {
FILE: Bit-mask/Bitmask_Basic.cpp
function erase_or_add (line 11) | void erase_or_add(int n, int& subset)
function display (line 15) | void display(int subset)
function main (line 28) | int main()
FILE: DP/LCS.cpp
function LCS (line 14) | void LCS(string a, string b) {
function LCS_SpaceOptmized (line 53) | void LCS_SpaceOptmized(string a, string b) {
function main (line 74) | int main() {
FILE: DP/LIS.cpp
function length_LIS (line 11) | int length_LIS(int arr[], int n)
function lengthLIS1 (line 28) | int lengthLIS1(vector<int> arr) {
function find_LIS (line 42) | void find_LIS(int arr[], int n) {
function find_LIS_Optimizd (line 60) | void find_LIS_Optimizd(int arr[],int n)
function main (line 95) | int main()
FILE: DP/LongestPalindromicSubstring.cpp
class Solution (line 16) | class Solution {
method string (line 18) | string longestPalindromeicSubString(string s) {
FILE: DP/LongestPanlidromicSubsequence.cpp
function LCS (line 14) | int LCS(string a, string b, int n, int m)
function longestPalindromeSubseq (line 31) | int longestPalindromeSubseq(string str)
function longestPalndromeSubsequenceOptimzed (line 51) | int longestPalndromeSubsequenceOptimzed(string str) {
function longestPalindromeSubseqUsingLCS (line 68) | int longestPalindromeSubseqUsingLCS(string s)
function main (line 75) | int main()
FILE: DP/PalindromicCuts.cpp
function isPalindrome (line 18) | bool isPalindrome(string str)
function findCuts (line 34) | int findCuts(string str, int l, int r)
function findCutsOptimized (line 70) | int findCutsOptimized(string str) {
function findCutsMostOptimized (line 109) | int findCutsMostOptimized(string str) {
function main (line 127) | int main()
FILE: DP/digit_dp.cpp
function digit_dp (line 13) | int digit_dp(string R,int n,int sum,bool tight)
function main (line 40) | int main()
FILE: DP/travelling_salesman_prob.cpp
function TSP (line 26) | int TSP(int visited,int position)
function main (line 46) | int main()
FILE: Graph/BFS.cpp
function addEdge (line 14) | void addEdge(int u, int v)
function bfs (line 20) | void bfs(int src)
function main (line 50) | int main()
FILE: Graph/Bellman_ford(Negative_weights).cpp
function bellman_ford (line 25) | void bellman_ford(int src)
function main (line 57) | int main()
FILE: Graph/Bipartite_Coloring.cpp
function addEdge (line 13) | void addEdge(int u, int v)
function bfs (line 19) | void bfs()
function main (line 72) | int main()
FILE: Graph/Bipartite_matching.cpp
function findMaxBiPartiteMatching (line 28) | bool findMaxBiPartiteMatching(int u) // applicant
function main (line 47) | int main()
FILE: Graph/DFS.cpp
function addEdge (line 18) | void addEdge(int u, int v)
function dfs_iterative (line 24) | void dfs_iterative(int src)
function dfs_recursive (line 49) | void dfs_recursive(int u)
function main (line 67) | int main()
FILE: Graph/FloydWarshall.cpp
function findShortestDist (line 16) | void findShortestDist(vector<vector<int>>& matrix) {
function main (line 36) | int main() {
FILE: Graph/cycleDetection.cpp
function isCyclicInDirectedGraph (line 17) | bool isCyclicInDirectedGraph(int n, vector<int> inDegree) {
function main (line 47) | int main() {
FILE: Graph/dijkstra.cpp
function addEdge (line 25) | void addEdge(int u, int v, int wt)
function dijktra (line 31) | void dijktra(int src)
function main (line 70) | int main()
FILE: Graph/prims_algo.cpp
function addEdge (line 26) | void addEdge(int u, int v, int wt)
function prim (line 32) | int prim()
function main (line 68) | int main()
FILE: Graph/topological_sort.cpp
function notIsCyclic (line 28) | bool notIsCyclic(int u)
function dfs (line 48) | void dfs(int u, stack<int>& stck)
function main (line 58) | int main()
FILE: Graph/union_find_algo.cpp
function init (line 19) | void init(int n)
function find (line 32) | int find(int x)
function weightedUnion (line 41) | void weightedUnion(int x, int y)
function main (line 64) | int main()
FILE: Greedy or DP (Problems)/Continuous_subarray_sum.cpp
function Find (line 2) | Find if is there any subarray with sum in multiple of k
FILE: Greedy or DP (Problems)/Job_scheduling.cpp
function jobScheduling (line 8) | int jobScheduling(vector<int>& startTime, vector<int>& endTime, vector<i...
FILE: Greedy or DP (Problems)/Kadane.cpp
function maxProductSubarray (line 16) | int maxProductSubarray(vector<int> arr) {
function max_pair (line 33) | int max_pair(vector<int> arr) {
FILE: Greedy or DP (Problems)/Queue_Reconstruction.cpp
function queue_reconstruction (line 11) | vector<pair<int,int>> queue_reconstruction(vector<pair<int,int>> people) {
FILE: Greedy or DP (Problems)/jump_problem.cpp
function min_jump (line 8) | int min_jump(vector<int> arr)
function main (line 30) | signed main()
FILE: NumberTheory/RandomNum.cpp
class Solution (line 20) | class Solution {
method Solution (line 24) | Solution(vector<int>& w) {
method pickIndex (line 31) | int pickIndex() {
FILE: OS Concept based algos/LRU-Cache.cpp
class LRUCache (line 15) | class LRUCache
method LRUCache (line 24) | LRUCache(int capacity)
method get (line 29) | int get(int key)
method put (line 42) | void put(int key, int value)
function main (line 63) | int main()
FILE: Range_queries/Range_Update(Difference_Array).cpp
function init (line 11) | void init(int arr[],int n)
function update_range (line 21) | void update_range(int arr[], int l, int r, int n, int x)
function print (line 31) | void print(int arr[], int n)
function main (line 42) | int main()
FILE: Range_queries/Segment_trees.cpp
function init_tree (line 20) | void init_tree(int node_indx,int node_lower,int node_upper)
function range_query (line 38) | int range_query(int node_indx, int a, int b, int node_lower, int node_up...
function update_point (line 57) | void update_point(int node_indx,int a,int node_lower, int node_upper, in...
function main (line 121) | int main()
FILE: Range_queries/sparce_table.cpp
function f (line 21) | int f(int a, int b)
function init (line 28) | void init(int arr[],int n)
function query_normal (line 40) | int query_normal(int l,int r)
function query_idempotent (line 58) | int query_idempotent(int l, int r)
function main (line 66) | int main(void)
FILE: Sorting Algorithms/HeapSort.cpp
function heapify (line 9) | void heapify(vector<int> &arr, int n, int i)
function heapSort (line 33) | void heapSort(vector<int> &arr, int n)
function print (line 53) | void print(vector<int> arr){
function main (line 60) | int main(){
FILE: Sorting Algorithms/Inbuilt_sorting_algos.cpp
function compare (line 6) | bool compare(int a, int b){
function main (line 10) | int main(){
FILE: Sorting Algorithms/MergeSort.cpp
function merge (line 8) | void merge(vector<int> &arr,int lo, int hi, int mid){
function mergeSort (line 26) | void mergeSort(vector<int> &arr, int lo, int hi) {
function print (line 37) | void print(vector<int> arr){
function main (line 44) | int main(){
FILE: Sorting Algorithms/O(n^2)_Algos.cpp
function insertionSort (line 7) | void insertionSort(vector<int> &arr){
function selectionSort (line 25) | void selectionSort(vector<int> &arr){
function bubbleSort (line 36) | void bubbleSort(vector<int> &arr){
function modified_bubbleSort (line 45) | void modified_bubbleSort(vector<int> &arr){
function print (line 59) | void print(vector<int> arr){
function main (line 66) | int main(){
FILE: Sorting Algorithms/QuickSort.cpp
function partition (line 11) | int partition(vector<int> &arr, int lo, int hi){
function quickSort (line 35) | void quickSort(vector<int> &arr, int lo, int hi){
function print (line 43) | void print(vector<int> arr){
function main (line 50) | int main(){
FILE: Sorting Algorithms/RadixSort.cpp
function countSort (line 13) | void countSort(vector<int>& arr, int exp) {
function radixSort (line 43) | void radixSort(vector<int> &arr){
function print (line 57) | void print(vector<int> arr){
function main (line 64) | int main(){
FILE: Sorting Algorithms/cycleSort.cpp
function cycleSort (line 7) | void cycleSort(vector<int>& arr, int n) {
function print (line 18) | void print(vector<int> arr){
function main (line 25) | int main(){
FILE: Strings/KMP.cpp
function computeLPSArray (line 22) | void computeLPSArray(char* pat, int M, int* lps)
function KMPSearch (line 59) | vector<int> KMPSearch(char* pat, char* txt)
function main (line 100) | int main(){
FILE: Strings/PatternMatching.cpp
function findModuloPower (line 29) | int findModuloPower(int a, int b, int q) {
function findStringHash (line 42) | int findStringHash(int d, int h,int q, string str) {
function findMatches (line 51) | vector<int> findMatches(string text, string pattern) {
function main (line 93) | int main() {
FILE: Strings/string_input.cpp
function main (line 7) | int main(){
FILE: Trees/Binary_Lifting.cpp
function addEdge (line 24) | void addEdge(int u, int v)
function binary_lifting (line 31) | void binary_lifting(int u, int pa)
function getKthAncestor (line 52) | int getKthAncestor(int node, int h)
function LCA (line 65) | int LCA(int a, int b)
function main (line 93) | int main()
FILE: Trees/LCA.cpp
class TreeNode (line 4) | class TreeNode
function TreeNode (line 12) | TreeNode* LCA_binaryTree(TreeNode* root, int n1, int n2) {
function TreeNode (line 31) | TreeNode* LCA_bst(TreeNode* root, int n1, int n2) {
function TreeNode (line 46) | TreeNode* newNode(int val)
function main (line 54) | int main(){
FILE: Trees/WordSearch2.cpp
class Solution (line 7) | class Solution {
type node (line 8) | struct node{ //TrieNode
type node (line 14) | struct node
method insert (line 27) | void insert(string s)
method solve (line 44) | void solve(vector<vector<char>>& board,int i,int j,int r,int c,vector<...
method findWords (line 76) | vector<string> findWords(vector<vector<char>>& board, vector<string>& ...
FILE: Trees/trie.cpp
type trie_tag (line 11) | struct trie_tag{
method trie_tag (line 15) | trie_tag(){isEnd = false;}
function insert (line 21) | void insert(string str)
function search (line 38) | bool search(string str)
function main (line 60) | int main(void)
FILE: codesnippet.cpp
function exp (line 18) | int exp(int x,int n)
function inv (line 29) | int inv(int x)
function ncr (line 34) | int ncr(int n,int r)
function solve (line 45) | int solve(int n)
function main_code (line 53) | void main_code()
function main (line 60) | signed main()
Condensed preview — 67 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (108K chars).
[
{
"path": ".gitignore",
"chars": 9,
"preview": ".vscode/*"
},
{
"path": "Adhoc + Basic/Reservoir_sampling.cpp",
"chars": 1698,
"preview": "/**\n * Question: Is there a way to get random number from a stream of integers?\n * Yes. We create a reserviour of size 1"
},
{
"path": "Adhoc + Basic/Sieve_of_Eratosthenes.cpp",
"chars": 1534,
"preview": "/*Questions solved\n\tprecomputation\t\t\t\t\t-> \tO(N(lnlnN))\n1.\tis n a prime\t\t\t\t\t->\tO(1)\n2.\tfactors of some F\t\t\t\t->\tO(ln NF)\n3"
},
{
"path": "Adhoc + Basic/Two_Pointer.cpp",
"chars": 497,
"preview": "// Dutch National Flag Problem\n// Sot 0,1,2 with a single traversal\n\n/*\n* Must satisfy condn\n* [start,lo] = 0\n* [hi+1,e"
},
{
"path": "Adhoc + Basic/binary_search_I.cpp",
"chars": 2993,
"preview": "// Question link -> https://community.topcoder.com/stat?c=problem_statement&pm=1901&rd=4650\n// Artical link -> https://w"
},
{
"path": "Adhoc + Basic/binary_search_II.cpp",
"chars": 3249,
"preview": "// Reference --> https://www.youtube.com/watch?v=U66U1-umNbQ&t=1s\n// Reference --> https://www.youtube.com/watch?v=V343U"
},
{
"path": "Adhoc + Basic/binary_search_III.cpp",
"chars": 931,
"preview": "#include<bits/stdc++.h>\n\nusing namespace std;\n\nint lowerBound(vector<int> arr, int target) {\n int left = 0;\n int r"
},
{
"path": "Arrays/MedianOfSortedArrays.cpp",
"chars": 2128,
"preview": "// Problem Link : https://leetcode.com/problems/median-of-two-sorted-arrays/\n/*\n\nIf we merge two arrays in sorted manner"
},
{
"path": "Arrays/MedianOfStream.cpp",
"chars": 1322,
"preview": "/*\n\n\tTime complexity: O(N*(log(N))) \n\tSpace complexity: O(N)\n\t\n\twhere N is the total number of elements in the array.\n\n*"
},
{
"path": "Arrays/MonotonicStack.cpp",
"chars": 1806,
"preview": "/**\n * @file MonotonicStack.cpp\n * @author Nisarg \n * @brief A monotonic stack is a stack whose elements are monotonical"
},
{
"path": "Arrays/Sliding Window Max.cpp",
"chars": 189,
"preview": "/**\n * https://leetcode.com/problems/sliding-window-maximum/solutions/5503612/best-code-in-c-must-see-easy-to-understand"
},
{
"path": "Arrays/TrappingRainwater.cpp",
"chars": 1071,
"preview": "#include<bits/stdc++.h>\r\nusing namespace std;\r\n\r\nclass Solution {\r\npublic:\r\n int trap(vector<int>& height) {\r\n "
},
{
"path": "Arrays/readme.md",
"chars": 137,
"preview": "Deletion in a vector takes O(1) time if order doesn't matter.\nDelete ith indexed value.\n\n```\nswap(arr[i], arr[n-1]);\narr"
},
{
"path": "Bit-mask/Bitmask_Basic.cpp",
"chars": 1047,
"preview": "// Reference -> https://www.youtube.com/watch?v=7FmL-WpTTJ4\n// We are using bitmask to store the numbers between 1 and 1"
},
{
"path": "DP/LCS.cpp",
"chars": 1988,
"preview": "/**\n * @file LCS.cpp\n * @author Nisarg\n * @brief Longest comman Subsequence in given two strings\n * NOT HERE APPLICABLE:"
},
{
"path": "DP/LIS.cpp",
"chars": 2731,
"preview": "/*\nLongest Increasing Subsequence\nComplexity for LIS Algo -> O(NlogN) \nN-number of elements\n*/\n\n#include<bits/stdc++.h>"
},
{
"path": "DP/LongestPalindromicSubstring.cpp",
"chars": 2068,
"preview": "#include<bits/stdc++.h>\nusing namespace std;\n\n/* solution is based on gap strategy\nReference --> https://www.youtube.co"
},
{
"path": "DP/LongestPanlidromicSubsequence.cpp",
"chars": 2463,
"preview": "/**\n * @file LongestPanlidromicSubsequence.cpp\n * @author Nisarg Gogate\n * @brief Find Longest palindrome subsequence\n *"
},
{
"path": "DP/MatrixChainMulti.cpp",
"chars": 249,
"preview": "// We use this techinique when we have to put brackets in the given list based on some condn.\n// This solution is used w"
},
{
"path": "DP/PalindromicCuts.cpp",
"chars": 3556,
"preview": "/**\n * @file PalindromicCut.cpp\n * @author Nisarg Gogate\n * @brief Cases when we want to divide array/string into parts "
},
{
"path": "DP/digit_dp.cpp",
"chars": 1334,
"preview": "// Reference -> https://www.youtube.com/watch?v=heUFId6Qd1A\n// F(x) returns boolean value\n// General -> How many integer"
},
{
"path": "DP/travelling_salesman_prob.cpp",
"chars": 1603,
"preview": "// Reference -> https://www.youtube.com/watch?v=QukpHtZMAtM&list=PLb3g_Z8nEv1icFNrtZqByO1CrWVHLlO5g&index=4\n// Reference"
},
{
"path": "Geometry/anglecoverted.cpp",
"chars": 103,
"preview": "// given question : https://leetcode.com/discuss/interview-question/5567668/Google-Interview-Onsite-1\n\n"
},
{
"path": "Graph/BFS.cpp",
"chars": 1567,
"preview": "#include<bits/stdc++.h>\n// Time Complexity: O(V + E)\n// A slight modification of question: Find 2nd fastest way of reach"
},
{
"path": "Graph/Bellman_ford(Negative_weights).cpp",
"chars": 1723,
"preview": "/*\nReference -> https://www.youtube.com/watch?v=FtN3BYH2Zes\nMinimum distance of src from every other node present in gra"
},
{
"path": "Graph/Bipartite_Coloring.cpp",
"chars": 1745,
"preview": "#include<bits/stdc++.h>\n\nusing namespace std;\n#define LIM 1007\ntypedef enum {WHITE,GREY,BLACK} col;\n// we try ro color w"
},
{
"path": "Graph/Bipartite_matching.cpp",
"chars": 2105,
"preview": "/**\n * @file Bipartite_matching.cpp\n * @author Nisarg\n * @brief Question: Given n job appplicants and m jobs. Given ith "
},
{
"path": "Graph/DFS.cpp",
"chars": 1537,
"preview": "\n/*\nWe can peform multisorurce bfs also for the problems of type \n1. there are k hospitals and n cities and they are co"
},
{
"path": "Graph/FloydWarshall.cpp",
"chars": 1508,
"preview": "/**\n * @file FloydWarshall.cpp\n * @author Nisarg\n * @brief Multi Source shortest path algorithm. Find shortest paths fro"
},
{
"path": "Graph/README.md",
"chars": 695,
"preview": "# Graphs\n\nMinimum Spanning Tree\n- **Prim's Algorithm**: Add `{wt, node}` to min heap to visit all nodes only once.\n\n\nSho"
},
{
"path": "Graph/cycleDetection.cpp",
"chars": 1247,
"preview": "/**\n * @file cycleDetection.cpp\n * @author Nisarg\n * @date 2024-07-27\n * \n * Detect cycle in directed and adirected grap"
},
{
"path": "Graph/dijkstra.cpp",
"chars": 2564,
"preview": "/*\nA minimum distance of src from every other node present in graph with all non-negative weights (optimized algo) OR Ne"
},
{
"path": "Graph/prims_algo.cpp",
"chars": 1835,
"preview": "/*\nMinimum Spanning tree is (minimum sum) tree with V-1 edges\nTotal sum of all the edges must be minimum in O(ElnV)\nE-Ed"
},
{
"path": "Graph/topological_sort.cpp",
"chars": 1984,
"preview": "// Not necessarily unique\n// Acyclic graph and directed graph\n/* \n Que -> https://cses.fi/problemset/task/1679 \n T"
},
{
"path": "Graph/union_find_algo.cpp",
"chars": 2060,
"preview": "/*\n Que: Given a list of operation makeFriends(a,b) and areFriends(a,b)\n These methods makes a and b friends or ch"
},
{
"path": "Greedy or DP (Problems)/Continuous_subarray_sum.cpp",
"chars": 409,
"preview": "// Link --> https://leetcode.com/problems/continuous-subarray-sum/\nFind if is there any subarray with sum in multiple of"
},
{
"path": "Greedy or DP (Problems)/Job_scheduling.cpp",
"chars": 1338,
"preview": "// Link --> https://leetcode.com/problems/maximum-profit-in-job-scheduling/\n\n// You're given the startTime, endTime and "
},
{
"path": "Greedy or DP (Problems)/Kadane.cpp",
"chars": 1427,
"preview": "// Find max_sum of sub array\n// Question? Why should curr_sum start with arr[i] and not with something before ith index?"
},
{
"path": "Greedy or DP (Problems)/Queue_Reconstruction.cpp",
"chars": 1237,
"preview": "/*Given n peps with [hi,ki] where ki denotes number of peps with height\n* greater than or eqaul to hi to its left in fin"
},
{
"path": "Greedy or DP (Problems)/jump_problem.cpp",
"chars": 990,
"preview": "// Link : https://leetcode.com/problems/jump-game-ii/\n// Reach from 0th index to nth index with minimum number of jumps\n"
},
{
"path": "Greedy or DP (Problems)/variations.txt",
"chars": 466,
"preview": "1. Find maximum no. of intervals to select with no overlap. (Jump Scheduling - I)\n--> Jump Problem (DP but like Kedans)\n"
},
{
"path": "Matrix or Backtracking(Problems)/Max_Submatrix_with_LT_Ksum.cpp",
"chars": 679,
"preview": "// Maximum size square Sub-Matrix with sum less than or equals to K\n// Link -> geeksforgeeks.org/maximum-size-square-sub"
},
{
"path": "NumberTheory/RandomNum.cpp",
"chars": 1130,
"preview": "/**\n * @file RandomNum.cpp\n * @author Nisarg Gogate\n *\n * Finding random number between 0 and n-1\n * 1. rand() % n - It "
},
{
"path": "OS Concept based algos/LRU-Cache.cpp",
"chars": 1425,
"preview": "// We can use stl container list as a double\n// ended queue to store the cache keys, with\n// the descending time of refe"
},
{
"path": "README.md",
"chars": 1546,
"preview": "# Algorithm Implementations\n\nWe have not written all of these algos ourselves. This is merely a small collection of easy"
},
{
"path": "Range_queries/Mo's_algo.cpp",
"chars": 61,
"preview": "// Find number of elements ocuuring only once in range [L,R]."
},
{
"path": "Range_queries/Persisitant tree.cpp",
"chars": 0,
"preview": ""
},
{
"path": "Range_queries/Range_Update(Difference_Array).cpp",
"chars": 1511,
"preview": "// Reference link -> https://www.geeksforgeeks.org/difference-array-range-update-query-o1/\n// Range update in time compl"
},
{
"path": "Range_queries/Segment_trees.cpp",
"chars": 4118,
"preview": "//Segment tree for sum range-queries and updation\n/*\none-based indexing\nLIM=N\n1. Initialization -> O(N)\n2. Range sum q"
},
{
"path": "Range_queries/sparce_table.cpp",
"chars": 2332,
"preview": "// Reference -> https://www.youtube.com/watch?v=2EpX9LkO2T0\n// Refernece -> https://youtu.be/0jWeUdxrGm4\n// NOTE : We ca"
},
{
"path": "Range_queries/sqrt_decomposition.cpp",
"chars": 0,
"preview": ""
},
{
"path": "Range_queries/which_to_use_when.txt",
"chars": 64,
"preview": "If we need to make range update Seg_tree will most likely work\n\n"
},
{
"path": "Sorting Algorithms/HeapSort.cpp",
"chars": 1629,
"preview": "// Given an array implementation of Complete Binary Tree\n// Heapify function takes O(logn) \n// n is the size of array.\n#"
},
{
"path": "Sorting Algorithms/Inbuilt_sorting_algos.cpp",
"chars": 789,
"preview": "#include<bits/stdc++.h>\n\nusing namespace std;\n\n// Keep variables static to avoid some error\nbool compare(int a, int b){\n"
},
{
"path": "Sorting Algorithms/MergeSort.cpp",
"chars": 1112,
"preview": "// Merge Sort O(nlog(n)) with O(n) space\n// else O(nlog^2(n)) with O(1) space\n\n#include<bits/stdc++.h>\n\nusing namespace "
},
{
"path": "Sorting Algorithms/O(n^2)_Algos.cpp",
"chars": 1867,
"preview": "#include<bits/stdc++.h>\nusing namespace std;\n\n// Insertion Sort\n// We divide an array into 2 parts one is sorted and oth"
},
{
"path": "Sorting Algorithms/QuickSort.cpp",
"chars": 1580,
"preview": "// O(nlog(n)) --> average time Complexcity \n// O(n^2) --> worst case (If 1st element is chosen as pivot and arr is"
},
{
"path": "Sorting Algorithms/RadixSort.cpp",
"chars": 1930,
"preview": "#include<bits/stdc++.h>\nusing namespace std;\n\n// Time Complexcity = O(d*n) \n// where d is max no. of digits in a number "
},
{
"path": "Sorting Algorithms/cycleSort.cpp",
"chars": 640,
"preview": "// Given array of size n has elements from 0 to n-1.\n// Sorting can be done in O(n) using cycleSort\n#include<bits/stdc++"
},
{
"path": "Strings/KMP.cpp",
"chars": 2236,
"preview": "// String comapre Algo with O(m+n) m,n being lenghts of string to compare\n\n/* \n* IDEA - Is prefix of pattern again apper"
},
{
"path": "Strings/PatternMatching.cpp",
"chars": 3335,
"preview": "// Given a large text and a pattern where text >> pattern.\n// Find indices for the matching pattern in the text.\n\n// Rol"
},
{
"path": "Strings/string_input.cpp",
"chars": 726,
"preview": "// If the input format of a string is know...\n// Ex.str = \"233+923i\" How to extract numbers\n\n#include<bits/stdc++.h>\nusi"
},
{
"path": "Trees/Binary_Lifting.cpp",
"chars": 2563,
"preview": "// Note : Is apllicable only on trees\n// Precomutation : NLog(N)\n// Query output (to find LCA as well as kth ancestor) :"
},
{
"path": "Trees/LCA.cpp",
"chars": 1757,
"preview": "#include<bits/stdc++.h>\nusing namespace std;\n\nclass TreeNode\n{\n public:\n int val;\n TreeNode *left, *rig"
},
{
"path": "Trees/WordSearch2.cpp",
"chars": 2541,
"preview": "#include<bits/stdc++.h>\nusing namespace std;\n\n// Problem Link : https://leetcode.com/problems/word-search-ii/\n// Code ta"
},
{
"path": "Trees/trie.cpp",
"chars": 1302,
"preview": "// Reference -> https://www.geeksforgeeks.org/trie-memory-optimization-using-hash-map/\n// NOTE : \n\n#include<bits/stdc++."
},
{
"path": "codesnippet.cpp",
"chars": 1179,
"preview": "// Nisarg Gogate\n// VNIT\n\n#include<bits/stdc++.h>\n#define DEBUG_ON 0\n#define int long long \n#define TESTCASES false\n#def"
}
]
About this extraction
This page contains the full source code of the nisarg0/Algorithm-Implementation GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 67 files (96.9 KB), approximately 30.6k tokens, and a symbol index with 173 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.