Count of Smaller Numbers After Self - MergeSort based concise solution
Problem Statement:
Given an integer array nums
, return an integer array counts
where counts[i]
is the number of smaller elements to the right of nums[i]
.
Example 1:
Input: nums = [5,2,6,1] Output: [2,1,1,0] Explanation: To the right of 5 there are 2 smaller elements (2 and 1). To the right of 2 there is only 1 smaller element (1). To the right of 6 there is 1 smaller element (1). To the right of 1 there is 0 smaller element.
Example 2:
Input: nums = [-1] Output: [0]
Example 3:
Input: nums = [-1,-1] Output: [0,0]
Constraints:
1 <= nums.length <= 105
-104 <= nums[i] <= 104
Solution:
Here is a typical pseudocode for mergeSort
:
void mergeSort(vector<int>&A, int lo, int hi)
{
int mid = lo+(hi-lo)/2;
mergeSort(A,lo,mid);
mergeSort(A,mid+1,hi);
merge(); // merge logic in same or separate function
}
Now in the merge logic we typically have this kind of logic:
int i=0, j=0, k=0, n1=L.size(), n2=R.size();
vector<int> A(n1+n2);
while(i<n1 && j<n2) if(L[i]<=R[j]) A[k++]=L[i++]; else A[k++]=R[j++];
while(i<n1) A[k++]=L[i++];
while(j<n2) A[k++]=R[j++];
This is for ascending order. For descending order, we just invert the inequality sign.
Now, for our question, if we store the indices with the values in pair<int,int>
format, then we can modifty the merge
logic to incorporate counting “Lower To the Right” logic.
This can be done in multiple ways as shown below:
Solution 1: Sort in ascending order
#define pii pair<int,int>
class Solution {
vector<int>res;
public:
void mergeSort(vector<pii>&A, int lo, int hi)
{
if (lo==hi) return;
int mid = lo + (hi-lo)/2;
mergeSort(A, lo, mid);
mergeSort(A,mid+1,hi);
vector<pii> L(A.begin()+lo,A.begin()+mid+1);
vector<pii> R(A.begin()+mid+1,A.begin()+hi+1);
int n1=L.size(), n2=R.size(), i=0, j=0, k=lo, ctr=0;
while(i<n1 && j<n2)
{
if(L[i].first<=R[j].first)
{
res[L[i].second] += ctr;
A[k++]=L[i++];
}
else
{
ctr++;
A[k++]=R[j++];
}
}
while(i<n1)
{
res[L[i].second] += ctr;
A[k++]=L[i++];
}
while(j<n2) A[k++]=R[j++];
}
vector<int> countSmaller(vector<int>& nums)
{
int n = nums.size();
res.resize(n,0);
vector<pii> pairs;
for(int i=0; i<n; i++) pairs.push_back({nums[i],i});
mergeSort(pairs,0,n-1);
for(auto k: pairs) cout<<k.first<<',';
return res;
}
};
Solution 2: Sort in descending order
#define pii pair<int,int>
class Solution {
vector<int>res;
public:
void mergeSort(vector<pii>&A, int lo, int hi)
{
if (lo==hi) return;
int mid = lo + (hi-lo)/2;
mergeSort(A, lo, mid);
mergeSort(A,mid+1,hi);
vector<pii> L(A.begin()+lo,A.begin()+mid+1);
vector<pii> R(A.begin()+mid+1,A.begin()+hi+1);
int n1=L.size(), n2=R.size(), i=0, j=0, k=lo;
while(i<n1 && j<n2) if(L[i].first>R[j].first)
{
res[L[i].second]+=(n2-j);
A[k++]=L[i++];
} else A[k++]=R[j++];
while(i<n1) A[k++]=L[i++];
while(j<n2) A[k++]=R[j++];
}
vector<int> countSmaller(vector<int>& nums)
{
int n = nums.size();
res.resize(n,0);
vector<pii> pairs;
for(int i=0; i<n; i++) pairs.push_back({nums[i],i});
mergeSort(pairs,0,n-1);
// for(auto k: pairs) cout<<k.first<<',';
return res;
}
};