@@ -582,4 +582,160 @@ func merge(arr []Pair, low, mid, high int) {
582582
583583<!-- solution:end -->
584584
585+ <!-- solution:start -->
586+
587+ ### Solution 3: Merge Sort
588+
589+ During the merge phase of merge sort, when a left element $\textit{left}[ i] \leq \textit{right}[ j] $,
590+ it means exactly $j$ elements on the right side are smaller than $\textit{left}[ i] $,
591+ so we accumulate $j$ into the count of $\textit{left}[ i] $.
592+
593+ Once all right elements are exhausted, all right elements are smaller than
594+ each remaining left element, so we accumulate the right array's full length
595+ into each remaining left element's count.
596+
597+ ** Note:** In C++, merge sort on very large arrays may suffer Memory Limit Exceeded.
598+ Use a buffer array to avoid excessive memory allocations.
599+
600+ #### Complexity
601+
602+ - Time complexity: $O(n \log n)$, the standard time complexity for merge sort.
603+ - Space complexity: $O(n)$, the standard space complexity of recursion stack.
604+
605+ <!-- tabs:start -->
606+
607+ #### Python3
608+
609+ ``` python
610+ class Solution :
611+ def countSmaller (self , nums : list[int ]) -> list[int ]:
612+ self .right_smaller_counts = [0 ] * len (nums)
613+
614+ nums_indices = [(num, idx) for idx, num in enumerate (nums)]
615+ self .merge_sort(nums_indices)
616+
617+ return self .right_smaller_counts
618+
619+ def combine_arrays (
620+ self ,
621+ left_nums_indices : list[tuple[int , int ]],
622+ right_nums_indices : list[tuple[int , int ]],
623+ ) -> list[tuple[int , int ]]:
624+ merged_nums_indices: list[tuple[int , int ]] = []
625+ left_idx, right_idx = 0 , 0
626+
627+ while left_idx < len (left_nums_indices) and right_idx < len (right_nums_indices):
628+ if left_nums_indices[left_idx][0 ] <= right_nums_indices[right_idx][0 ]:
629+ # Iterated left side element finalizes its right smaller count.
630+ left_num_idx = left_nums_indices[left_idx][1 ]
631+ self .right_smaller_counts[left_num_idx] += right_idx
632+
633+ merged_nums_indices.append(left_nums_indices[left_idx])
634+ left_idx += 1
635+ continue
636+
637+ merged_nums_indices.append(right_nums_indices[right_idx])
638+ right_idx += 1
639+
640+ while left_idx < len (left_nums_indices):
641+ # Iterated left side element finalizes its right smaller count.
642+ left_num_idx = left_nums_indices[left_idx][1 ]
643+ self .right_smaller_counts[left_num_idx] += len (right_nums_indices)
644+
645+ merged_nums_indices.append(left_nums_indices[left_idx])
646+ left_idx += 1
647+
648+ while right_idx < len (right_nums_indices):
649+ merged_nums_indices.append(right_nums_indices[right_idx])
650+ right_idx += 1
651+
652+ return merged_nums_indices
653+
654+ def merge_sort (self , nums_indices : list[tuple[int , int ]]) -> list[tuple[int , int ]]:
655+ if len (nums_indices) == 1 :
656+ return nums_indices # Single element.
657+
658+ split_idx = len (nums_indices) // 2
659+
660+ left_nums_indices = self .merge_sort(nums_indices[:split_idx])
661+ right_nums_indices = self .merge_sort(nums_indices[split_idx:])
662+
663+ return self .combine_arrays(left_nums_indices, right_nums_indices)
664+ ```
665+
666+
667+ #### C++
668+
669+ ``` cpp
670+ class Solution {
671+ private:
672+ vector<int > rightSmallerCounts;
673+ vector<pair<int, int>> buffer;
674+
675+ void combineArrays(
676+ vector<pair<int, int>>& numsIndices, int leftBound, int splitIdx, int rightBound) {
677+ // Left side array = numsIndices[leftBound: splitIdx].
678+ // Right side array = numsIndices[splitIdx: rightBound + 1].
679+ int leftIdx = leftBound, rightIdx = splitIdx;
680+ int bufferIdx = leftBound;
681+
682+ while (leftIdx < splitIdx && rightIdx <= rightBound) {
683+ if (numsIndices[leftIdx].first <= numsIndices[rightIdx].first) {
684+ // Iterated left side element finalizes its right smaller count.
685+ int leftNumIdx = numsIndices[leftIdx].second;
686+ rightSmallerCounts[leftNumIdx] += rightIdx - splitIdx;
687+
688+ buffer[bufferIdx++] = numsIndices[leftIdx++];
689+ }
690+
691+ else
692+ buffer[bufferIdx++] = numsIndices[rightIdx++];
693+ }
694+
695+ while (leftIdx < splitIdx) {
696+ // Iterated left side element finalizes its right smaller count.
697+ int leftNumIdx = numsIndices[leftIdx].second;
698+ rightSmallerCounts[leftNumIdx] += rightIdx - splitIdx;
699+
700+ buffer[bufferIdx++] = numsIndices[leftIdx++];
701+ }
702+
703+ while (rightIdx <= rightBound)
704+ buffer[bufferIdx++] = numsIndices[rightIdx++];
705+
706+ for (int idx = leftBound; idx <= rightBound; idx++)
707+ numsIndices[idx] = buffer[idx]; // Put buffer data back to original array.
708+ }
709+
710+ void mergeSort(vector<pair<int, int>>& numsIndices, int leftBound, int rightBound) {
711+ if (leftBound == rightBound) return; // Single element.
712+
713+ // Plus 1: ensure splitIdx > leftBound.
714+ int splitIdx = (leftBound + rightBound + 1) / 2;
715+
716+ mergeSort (numsIndices, leftBound, splitIdx - 1);
717+ mergeSort(numsIndices, splitIdx, rightBound);
718+
719+ combineArrays (numsIndices, leftBound, splitIdx, rightBound);
720+ }
721+
722+ public:
723+ vector<int > countSmaller(vector<int >& nums) {
724+ buffer.resize(nums.size()); // Against memory explosions.
725+
726+ vector<pair<int, int>> numsIndices(nums.size());
727+ for (int idx = 0; idx < nums.size(); idx++)
728+ numsIndices[idx] = {nums[idx], idx};
729+
730+ rightSmallerCounts.assign(nums.size(), 0);
731+ mergeSort (numsIndices, 0, nums.size() - 1);
732+ return rightSmallerCounts;
733+ }
734+ };
735+ ```
736+
737+ <!-- tabs:end -->
738+
739+ <!-- solution:end -->
740+
585741<!-- problem:end -->
0 commit comments