"Array Algorithms: Three Sum, Sorting, and More"
"Array Algorithms: Three Sum, Sorting, and More"
1. ARRAY
Three sum : sum is 0 of three elements and unique numbers only.
3 loop approach
A+ b+c = 0 so use a+b = -c
Sort array and use three pointers , start end and middle , since array is sorted run j between
start and end. If satisfies put in ans. After loop reduce end and increase start
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> ans;
sort([Link](),[Link]());
int n = [Link]();
for(int i = 0;i<n;i++){
if(i>0 && nums[i-1]==nums[i]) continue;
int j =i+1;
int k = n-1;
while(j<k){
int sum = nums[i]+nums[k]+nums[j];
if(sum<0){
j++;
}else if(sum>0){
k--;
}else{
vector<int> temp ={nums[i],nums[j],nums[k]};
ans.push_back(temp);
j++;
k--;
while(j<k && nums[j-1]==nums[j]){
j++;
}
while(mid<=high){
if(nums[mid]==0){
swap(nums[low],nums[mid]);
low++;
mid++;
}
else if(nums[mid]==1){
mid++;
}else{
swap(nums[mid],nums[high]);
high--;
}
}
}
Majority element
Given an integer array nums of size n. Return all elements which appear more than n/3 times
in the array. The output can be returned in any order.
Take each element and run in loop , if times n/3> then put in ans;
O(N ) 2
Use a unordered map and put all elements, return all with times>n/3
0(nlogn) For using a map data structure, where insertion in the map
takes logN time
Best
For n>2 we use element and a count,take and element and increase count if u see it else -1, if
count is less than 0 change element. Do till last and you have your element
For n/3
n/3+n/3+n/3
Initialize 4 variables: cnt1 & cnt2 for tracking the counts of elements and el1 & el2 for
storing the majority of elements.
Traverse through the given array. If cnt1 is 0 and the current element is not el2 then store
the current element of the array as el1 along with increasing the cnt1 value by 1.
If cnt2 is 0 and the current element is not el1 then store the current element of the array as
el2 along with increasing the cnt2 value by 1.
If the current element and el1 are the same increase the cnt1 by 1 and if the current
element and el2 are the same increase the cnt2 by 1.
Other than all the above cases decrease cnt1 and cnt2 by 1. The integers present in el1 &
el2 should be the result we are expecting. So, using another loop, to manually check their
counts if they are greater than the floor(N/3).
O(N) + O(N), where N is size of the given array. The first O(N) is to
calculate the counts and find the expected majority elements. The
second one is to check if the calculated elements are the majority
ones or not.
vector<int> majorityElementTwo(vector<int>& nums) {
int count1=0,count2=0;
int el1 = INT_MIN;
int el2 = INT_MIN;
int n = [Link]();
for(int i = 0;i<n;i++){
if(count1==0 && el2!=nums[i]){
el1=nums[i];
count1=1;
}else if(count2==0 && el1!=nums[i]){
el2=nums[i];
count2=1;
}
else if(nums[i] == el1) count1++;
else if(nums[i] == el2) count2++;
else {
count1--;
count2--;
}
}
vector<int> ls;
count1=0,count2=0;
for(int i=0;i<n;i++){
if(nums[i]==el1)count1++;
if(nums[i]==el2)count2++;
}
int mini = (int)(n/3)+1;
if(count1>=mini)ls.push_back(el1);
if(count2>=mini)ls.push_back(el2);
return ls;
}
Return the values A and B, as an array of size 2, where A appears in the 0-th index
and B in the 1st index.
Brute:
Iterate in array from 1 to N & for each integer, i, count its occurrence in the given array
using linear search.
Store those two elements that have the occurrence of 2 and 0. Finally, return the elements.
O(N^2)
Best
Use maths and xor
Sum formula S1= n(n-1)/2
X-Y = S1 - sum of array list = A
Find sum of square
S2 = n(n-1)(2n-1)/6
S2- sum of squares = X2-Y2
S2/S1=X+Y = B
X=(A+B/2)
Y=(B-A/2)
Or use XOR
Xor till n elements and xor of array elements redo it
Best :
Approach:
Initialize a variable to store the maximum product result.
Maintain two running products: one for the prefix (left to right traversal) and one for the
suffix (right to left traversal).
Iterate through the array:
If the running product becomes zero, reset it to one to start a new subarray.
Update the prefix product with the current element during the left-to-right traversal.
Update the suffix product with the current element during the right-to-left traversal.
At each step, compute the maximum product using the current prefix and suffix products.
Return the maximum product obtained after the traversal.
int maxProduct(vector<int>& arr) {
int pre = 1,suff=1;
int ans = INT_MIN;
int n = [Link]();
for(int i=0;i<n;i++){
if(pre == 0) pre=1;
if(suff == 0) suff=1;
Reverse Pairs
Given an integer array nums. Return the number of reverse pairs in the array.
An index pair (i, j) is called a reverse pair if:
int mid=(low+high)/2;
int count=0;
count+= mergeSort(nums, low, mid);
count+= mergeSort(nums, mid+1, high);
count+= countPairs(nums, low, mid,high);
merge(nums,low,mid,high);
return count;
}
void merge(vector<int>& nums, int low, int mid, int high) {
vector<int> temp;
int left = low, right = mid + 1;
// Merge process
while (left <= mid && right <= high) {
if (nums[left] <= nums[right]) {
temp.push_back(nums[left++]);
} else {
temp.push_back(nums[right++]);
}
}
return cnt;
}
};
O(2n logn)
Each hour, the monkey chooses a non-empty pile of bananas and eats k bananas. If
the pile contains fewer than k bananas, the monkey eats all the bananas in that pile
and does not consume any more bananas in that hour.
Determine the minimum number of bananas the monkey must eat per hour to finish
all the bananas within h hours.
Linear search
Approach:
Working of minimumRateToEatBananas(nums, h):
First find out the maximum element in array by calling the 'findMax()'.
Then , iterate from 1 to max which signifies the number of bananas eaten per hour, and for
each iteration find out the hour taken to eat those bananas by calling calculateToatalHours ().
If the calculated hour is less than or equal to given limit, return the current value of
iteration(number of bananas) as an answer.
If no suitable answer is found, return max element as an answer.
Working of findMax(arr):
First initialize a variable 'maxi', which will store maximum element of the array.
Now, literate through the array and find the maximum element among them, and return it.
Working of calculateTotalHours(arr,hourly):
Start with initializing n = size of array, which gives the number of elements in the array.
Initialize 'totalH' to 0, which will accumulate the total hours required. 'hourly' represents the
number of items that can be processed per hour.
Compute the number of hours required to eat all bananas at the rate of 'hourly' bananas per
hour and store in 'totalH'. Use ceil function to round up the division result to ensure that
partial hours are counted correctly when necessary. Ater the traversal has ended, return
'totalH' as answer.
O(max * N), where max is the maximum element in the array and
N is the size of the array. We are running nested loops. The outer
loop runs for max times in the worst case and the inner loop runs
for N times.
Binary search
Instead of taking linear do binary search,if time comes more choose mid as high-1 else low+1
Return low
int minimumRateToEatBananas(vector<int> nums, int h) {
int high = findMax(nums);
int low=1;
while(low<=high){
int mid=(low+high)/2;
long long time = calculatetotalhours(nums,mid);
if(time<=(long long)h){
high=mid-1;
}
else{
low=mid+1;
}
}
return low;
}
int calculatetotalhours(vector<int> nums,int k){
int time=0;
for(int i =0;i<[Link]();i++){
time+=ceil((double)nums[i]/(double)k);
}
return time;
}
int findMax(vector<int>&v){
int maxi=INT_MIN;
int n =[Link]();
for(int i = 0;i<n;i++){
maxi=max(maxi,v[i]);
}
return maxi;
}
Aggressive Cows
Given an array nums of size n, which denotes the positions of stalls, and an integer
k, which denotes the number of aggressive cows, assign stalls to k cows such that
the minimum distance between any two cows is the maximum possible. Find the
maximum possible minimum distance.
sort([Link](),[Link]());
int low=1;
int high=nums[n-1]-nums[0];
int ans=0;
while(low<=high){
int mid=(low+high)/2;
if(canweplace(nums,mid,k)==true){
low=mid+1;
ans=mid;
}else{
high=mid-1;
}
}
return high;
}
bool canweplace(vector<int> nums,int d,int k){
int n=[Link]();
int count=1;
int last=nums[0];
for(int i =1;i<n;i++){
if(nums[i]-last>=d){
count++;
last=nums[i];
}
if(count>=k) return true;
}
return false;
}
};
The median is defined as the middle value of a sorted list of numbers. In case the
length of the list is even, the median is the average of the two middle elements.
Approach:
Initaialize the two indices as ind2 = (n1+n2)/2 and ind1 = ((n1+n2)/2)-1. These indices are
showing the position of medians in the merged array. Also, declare the counter called ‘cnt’
and initialize it with 0.
Now, take two pointers i and j, where i points to the first element of arr1 and j points to the
first element of arr2.
Next, initialize a while loop, which will run till any one of the pointers crosses the size of
their respective array. If the element at pointer i is less than or equal to element at pointer j,
then check if 'cnt' is equal to any of the indices of the medians, if so, store the element at
index i. Then increase i and 'cnt' by 1. Otherwise, check if 'cnt' is equal to any of the indices
of the medians, if so, store the element at index j. Then increase j and 'cnt' by 1.
After that, traverse the left-out elements from both arrays and perform the above step.
If the total length i.e. (sum of size of both the arrays) is even, then median is the average of
the elements at ind1 and ind2. Else, median will be the element at indexind2
Tc = O(N1+N2)
Best
}
};
Combination sum II
Given collection of candidate numbers (candidates) and a integer [Link] all unique
combinations in candidates where the sum is equal to the [Link] can only be one usage
of each number in the candidates combination and return the answer in sorted order.
ANS
RECURSION
class Solution {
public:
vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
//your code goes here
vector<vector<int>> ans;
vector<int> nums;
sort([Link](),[Link]());
func(0,ans,nums,candidates,target);
return ans;
}
void func(int ind,vector<vector<int>> &ans,vector<int>& nums,vector<int>
&candidates,int sum){
if(sum==0){
ans.push_back(nums);
return;
}
if(sum<0 || ind==[Link]())return;
nums.push_back(candidates[ind]);
func(ind+1,ans,nums,candidates,sum-candidates[ind]);
nums.pop_back();
for(int i = ind + 1; i < [Link](); i++) {
if(candidates[i] != candidates[ind]) {
func(i, ans, nums, candidates, sum);
break;
}
}
}
};
Tc: O(2^N*N)
sc:O(N)
N queen
Return nxn chess board with n queens in each row,each col and no queen shall attack each
other
Ans:
TC: O(N!)
SC:O(N)
Day 3
Single Number - III
Given an array nums of length n, every integer in the array appears twice except for
two integers. Identify and return the two integers that appear only once in the array.
Return the two numbers in ascending order
for(int i=0;i<n;i++){
meetings.push_back({start[i],end[i]});
}
sort([Link](), [Link](),
[](const pair<int,int>& a, const pair<int,int>& b) {
return [Link] < [Link];
});
int count=1;
int limit=meetings[0].second;
for(int i=1;i<n;i++){
if(meetings[i].first>limit){
limit=meetings[i].second;
count++;
}
}
return count;
}
Day4
Sort a Linked List of 0's 1's and 2's
struct ListNode {
int val;
ListNode* next;
ListNode() {
val = 0;
next = NULL;
}
ListNode(int data1) {
val = data1;
next = NULL;
}
ListNode(int data1, ListNode* next1) {
val = data1;
next = next1;
}
};
ListNode *zero=zerohead;
ListNode *one = onehead;
ListNode *two = twohead;
ListNode *temp=head;
while(temp!=NULL){
if(temp->data==0){
zero->next=temp;
zero=temp;
}else if(temp->data==1){
one->next=temp;
one=temp;
}else{
two->next=temp;
two=temp;
}
temp=temp->next;
}
zero->next = (onehead->next) ? onehead->next : twohead->next;
one->next = twohead->next;
two->next=NULL;
head = zerohead->next;
delete zerohead;
delete onehead;
delete twohead;
return head;
}
class Solution {
public:
ListNode* reverseLL(ListNode* head){
ListNode* prev=NULL;
ListNode* curr=head;
while(curr!=NULL){
ListNode* nextNode=curr->next;
curr->next=prev;
prev=curr;
curr=nextNode;
}
return prev;
}
bool isPalindrome(ListNode* head) {
if(head==NULL||head->next==NULL)return true;
ListNode* slow=head;
ListNode* fast=head;
//find middle
while(fast->next != NULL && fast->next->next != NULL){
slow=slow->next;
fast=fast->next->next;
}
//reverse in
ListNode* newhead=reverseLL(slow->next);
ListNode *first=head;
ListNode *second=newhead;
while(second!=NULL){
if(first->val != second->val){
reverseLL(newhead);
return false;
}
first=first->next;
second=second->next;
}
reverseLL(newhead);
return true;
}
};
Tc:O(N)
SC:O(N)
Better: use fast and slow pointer
ListNode *findStartingPoint(ListNode *head) {
ListNode* slow=head;
ListNode* fast=head;
return NULL;
}
Tc:O(N) SC:O(1)
Do not change the values of the nodes, only change the links between nodes.
Brute: store all elements in array, reverse k size sub arrays. Put value
Tc : O(N+N+N)
SC : O(N)
Flattening of LL
Given a special linked list containing n head nodes where every node in the linked list
contains two pointers:
‘Next’ points to the next node in the list
‘Child’ pointer to a linked list where the current node is the head
Each of these child linked lists is in sorted order and connected by a 'child' pointer.
Flatten this linked list such that all nodes appear in a single sorted layer connected by the
'child' pointer and return the head of the modified list.
if(head->child){
head->child->next=NULL;
}
return head->child;
}
ListNode* flattenLinkedList(ListNode* &head) {
if(head==NULL||head->next==NULL){
return head;
}
ListNode* newHead=flattenLinkedList(head->next);
head=mergeTwoLL(head,newHead);
return head;
}
Given the heads of two linked lists A and B, containing positive integers. Find the node at
which the two linked lists intersect. If they do intersect, return the node at which the
intersection begins, otherwise return null.
The Linked List will not contain any cycles. The linked lists must retain their original
structure, given as per the input, after the function returns.
Use hash map In brute force, store nodes, count++, if node count ==2 return that node;
O(N+M)
O(N+M)
Or store 1 list and traverse other while checking
O(N+M)
O(N)
O(N+M+d)
O(1)
Approach:
If either of the two linked lists is empty, there is no
intersection, so return NULL.
Start one pointer at the head of the first linked list and
another at the head of the second linked list.
O(N+M)
O(1)
Note: For custom input, a n x 2 matrix is taken with each row having 2 values:[ val,
random_index] where,
val: an integer representing [Link]
random_index: index of the node (0 - n-1) that the random pointer points to,
otherwise -1.
Use hash map to store nodes,nodes copy
O(2N+logN)
O(2N)
The next greater element of an element in the array is the nearest element on the right that is
greater than the current element.
If there does not exist a next greater element for the current element, then the next greater
element for that element is -1.
vector<int> ans(n);
stack<int> st;
for(int i=n-1;i>=0;i--){
int curr=arr[i];
while(![Link]() && [Link]()<=curr){
[Link]();
}
if([Link]())
ans[i]=-1;
else
ans[i]=[Link]();
[Link](arr[i]);
}
return ans;
}
Asteroid Collision
You are given an integer array asteroids representing asteroids in a row. Each asteroid moves
at the same speed.
The absolute value of an asteroid represents its size. The sign of an asteroid represents its
direction: positive (+) means moving right, negative (-) means moving left.
Collision rules:
Return the state of the asteroids after all collisions as an array in the same order.
class Solution{
public:
vector<int> asteroidCollision(vector<int> &arr){
vector<int> st;
int n = [Link]();
for(int i=0;i<n;i++){
if(arr[i]>0) st.push_back(arr[i]);
else{
while(![Link]() && [Link]()>0 && [Link]()<abs(arr[i])){
st.pop_back();
}
if(![Link]() && [Link]()==abs(arr[i])){
st.pop_back();
}
else if([Link]() ||
[Link]() < 0){
st.push_back(arr[i]);
}
}
}
return st;
}
};
Optimal :
class Solution {
public:
vector<int> findNSE(vector<int> &arr) {
// Size of array
int n = [Link]();
// Stack
stack<int> st;
// Size of array
int n = [Link]();
// Stack
stack<int> st;
// Size of array
int n = [Link]();
// Stack
stack<int> st;
// Size of array
int n = [Link]();
// To store the answer
vector<int> ans(n);
// Stack
stack<int> st;
// Size of array
int n = [Link]();
// Size of array
int n = [Link]();
public:
/* Function to find the sum of
subarray ranges in each subarray */
long long subArrayRanges(vector<int> &arr) {
LRU Cache
Implement lru cache
class Node{
public:
int key,val;
Node* next;
Node* prev;
Node(){
key=val=-1;
next=prev=NULL;
}
Node(int k,int value){
key = k;
val=value;
next=prev=NULL;
}
};
class LRUCache {
map<int,Node*> mpp; //map datastructure
int cap; // capcaity
Node* head; // dummy
Node* tail; // tail
public:
LRUCache(int capacity) {
cap=capacity;
[Link]();
head = new Node();
tail = new Node();
head->next=tail;
tail->next=head;
}
node->val=value;
deleteNode(node);
insertAfterHead(node);
return;
}
if([Link]()==cap){
Node* node = tail->prev;
[Link](node->key);
deleteNode(node);
}
Node* newNode=new Node(key_,value);
mpp[key_]=newNode;
insertAfterHead(newNode);
}
};
Remove K Digits
Note: If removing k digits deletes all digits, return "0". The result must be a valid non-
negative integer without leading zeros.
Example 1
Input: nums = "541892", k = 2
Output: "1892"
Explanation: Removing the two digits 5 and 4 yields the smallest number, 1892.
Example 2
Input: nums = "1002991", k = 3
Output: "21"
Explanation: Remove the three digits 1(leading one), 9, and 9 to form the new
number 21(Note that the output must not contain leading zeroes) which is the
smallest.
for(int i=0;i<n;i++){
while(![Link]() && k>0 &&
([Link]() -'0')>(nums[i]-'0')){
[Link]();
k--;
}
[Link](nums[i]);
}
while(k>0 && ![Link]()){
[Link]();
k--;
}
if([Link]()) return "0";
string ans="";
while(![Link]()){
ans.push_back([Link]());
[Link]();
}
while([Link]()>0 && [Link]()=='0'){
ans.pop_back();
}
reverse([Link](),[Link]());
if([Link]()) return "0";
return ans;
}
Heapify algorithm
class Solution {
public:
void heapifyDown(vector<int> &arr,int ind){
int n = [Link]();
int smallest = ind;
return;
}
void heapify(vector<int> &nums, int ind, int val) {
int old = nums[ind];
nums[ind] = val;
if(old > val){
heapifyUp(nums,ind);
}else{
nums[ind]=val;
heapifyDown(nums,ind);
}
return;
}
};
Brute force : for each train between arrival and departure check if any more train comes and
return max overlaps
O(N^2)
OPTIMAL :
int findPlatform(vector<int>& Arrival, vector<int>& Departure){
//your code goes here
int n = [Link]();
sort([Link](),[Link]());
sort([Link](),[Link]());
int ans = 1;
int count = 1;
int i =1;
int j =0;
while(i<n && j<n){
if(Arrival[i]<=Departure[j]){
count++;
i++;
}
else{
count--;
j++;
}
ans=max(count,ans);
}
return ans;
}
just count the number of trains coming and going at a time using two pointers