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.
During the merge phase of merge sort, when a left element \(\textit{left}[i] \leq \textit{right}[j]\), it means exactly \(j\) elements on the right side are smaller than \(\textit{left}[i]\), so we accumulate \(j\) into the count of \(\textit{left}[i]\).
Once all right elements are exhausted, all right elements are smaller than each remaining left element, so we accumulate the right array's full length into each remaining left element's count.
Note: In C++, merge sort on very large arrays may suffer Memory Limit Exceeded. Use a buffer array to avoid excessive memory allocations.
Complexity
Time complexity: \(O(n \log n)\), the standard time complexity for merge sort.
Space complexity: \(O(n)\), the standard space complexity of recursion stack.
classSolution:defcountSmaller(self,nums:list[int])->list[int]:self.right_smaller_counts=[0]*len(nums)nums_indices=[(num,idx)foridx,numinenumerate(nums)]self.merge_sort(nums_indices)returnself.right_smaller_countsdefcombine_arrays(self,left_nums_indices:list[tuple[int,int]],right_nums_indices:list[tuple[int,int]],)->list[tuple[int,int]]:merged_nums_indices:list[tuple[int,int]]=[]left_idx,right_idx=0,0whileleft_idx<len(left_nums_indices)andright_idx<len(right_nums_indices):ifleft_nums_indices[left_idx][0]<=right_nums_indices[right_idx][0]:# Iterated left side element finalizes its right smaller count.left_num_idx=left_nums_indices[left_idx][1]self.right_smaller_counts[left_num_idx]+=right_idxmerged_nums_indices.append(left_nums_indices[left_idx])left_idx+=1continuemerged_nums_indices.append(right_nums_indices[right_idx])right_idx+=1whileleft_idx<len(left_nums_indices):# Iterated left side element finalizes its right smaller count.left_num_idx=left_nums_indices[left_idx][1]self.right_smaller_counts[left_num_idx]+=len(right_nums_indices)merged_nums_indices.append(left_nums_indices[left_idx])left_idx+=1whileright_idx<len(right_nums_indices):merged_nums_indices.append(right_nums_indices[right_idx])right_idx+=1returnmerged_nums_indicesdefmerge_sort(self,nums_indices:list[tuple[int,int]])->list[tuple[int,int]]:iflen(nums_indices)==1:returnnums_indices# Single element.split_idx=len(nums_indices)//2left_nums_indices=self.merge_sort(nums_indices[:split_idx])right_nums_indices=self.merge_sort(nums_indices[split_idx:])returnself.combine_arrays(left_nums_indices,right_nums_indices)
classSolution{private:vector<int>rightSmallerCounts;vector<pair<int,int>>buffer;voidcombineArrays(vector<pair<int,int>>&numsIndices,intleftBound,intsplitIdx,intrightBound){// Left side array = numsIndices[leftBound: splitIdx].// Right side array = numsIndices[splitIdx: rightBound + 1].intleftIdx=leftBound,rightIdx=splitIdx;intbufferIdx=leftBound;while(leftIdx<splitIdx&&rightIdx<=rightBound){if(numsIndices[leftIdx].first<=numsIndices[rightIdx].first){// Iterated left side element finalizes its right smaller count.intleftNumIdx=numsIndices[leftIdx].second;rightSmallerCounts[leftNumIdx]+=rightIdx-splitIdx;buffer[bufferIdx++]=numsIndices[leftIdx++];}elsebuffer[bufferIdx++]=numsIndices[rightIdx++];}while(leftIdx<splitIdx){// Iterated left side element finalizes its right smaller count.intleftNumIdx=numsIndices[leftIdx].second;rightSmallerCounts[leftNumIdx]+=rightIdx-splitIdx;buffer[bufferIdx++]=numsIndices[leftIdx++];}while(rightIdx<=rightBound)buffer[bufferIdx++]=numsIndices[rightIdx++];for(intidx=leftBound;idx<=rightBound;idx++)numsIndices[idx]=buffer[idx];// Put buffer data back to original array.}voidmergeSort(vector<pair<int,int>>&numsIndices,intleftBound,intrightBound){if(leftBound==rightBound)return;// Single element.// Plus 1: ensure splitIdx > leftBound.intsplitIdx=(leftBound+rightBound+1)/2;mergeSort(numsIndices,leftBound,splitIdx-1);mergeSort(numsIndices,splitIdx,rightBound);combineArrays(numsIndices,leftBound,splitIdx,rightBound);}public:vector<int>countSmaller(vector<int>&nums){buffer.resize(nums.size());// Against memory explosions.vector<pair<int,int>>numsIndices(nums.size());for(intidx=0;idx<nums.size();idx++)numsIndices[idx]={nums[idx],idx};rightSmallerCounts.assign(nums.size(),0);mergeSort(numsIndices,0,nums.size()-1);returnrightSmallerCounts;}};