Reverse Pairs
Description
Given an integer array nums, return the number of reverse pairs in the array.
A reverse pair is a pair (i, j) where:
0 <= i < j < nums.length, andnums[i] > 2 * nums[j]
In other words, you need to count how many ordered pairs of indices exist such that the element at the earlier index is strictly more than twice the element at the later index.
Examples
Example 1
Input: nums = [1, 3, 2, 3, 1]
Output: 2
Explanation: The reverse pairs are:
- (1, 4): nums[1] = 3 and nums[4] = 1. Check: 3 > 2 × 1 = 2. Yes, 3 > 2. This is a reverse pair.
- (3, 4): nums[3] = 3 and nums[4] = 1. Check: 3 > 2 × 1 = 2. Yes, 3 > 2. This is a reverse pair.
No other pair of indices satisfies nums[i] > 2 * nums[j], so the answer is 2.
Example 2
Input: nums = [2, 4, 3, 5, 1]
Output: 3
Explanation: The reverse pairs are:
- (1, 4): nums[1] = 4, nums[4] = 1. Check: 4 > 2 × 1 = 2. Yes. Reverse pair.
- (2, 4): nums[2] = 3, nums[4] = 1. Check: 3 > 2 × 1 = 2. Yes. Reverse pair.
- (3, 4): nums[3] = 5, nums[4] = 1. Check: 5 > 2 × 1 = 2. Yes. Reverse pair.
All three pairs involve index 4 (value 1), which is small enough that several earlier elements exceed twice its value.
Example 3
Input: nums = [5, 2]
Output: 1
Explanation: Only one pair exists: (0, 1). Check: nums[0] = 5 > 2 × nums[1] = 2 × 2 = 4. Yes, 5 > 4. So the answer is 1.
Constraints
- 1 ≤ nums.length ≤ 5 × 10^4
- -2^31 ≤ nums[i] ≤ 2^31 - 1
Editorial
Brute Force
Intuition
The most natural approach is to check every possible pair of indices (i, j) where i < j and see whether nums[i] > 2 * nums[j]. We use two nested loops: the outer loop fixes the left element, and the inner loop tries every element to its right.
Think of it like a teacher checking every pair of students' scores. For each student, the teacher looks at every student who came after them and asks: "Is the first student's score more than double the second student's score?" If yes, that is a reverse pair. The teacher counts all such pairs across the entire class.
Step-by-Step Explanation
Let's trace through with nums = [1, 3, 2, 3, 1]:
Step 1: Fix i = 0 (nums[0] = 1). Check all j > 0:
- j = 1: 1 > 2 × 3 = 6? No.
- j = 2: 1 > 2 × 2 = 4? No.
- j = 3: 1 > 2 × 3 = 6? No.
- j = 4: 1 > 2 × 1 = 2? No.
- count = 0.
Step 2: Fix i = 1 (nums[1] = 3). Check all j > 1:
- j = 2: 3 > 2 × 2 = 4? No.
- j = 3: 3 > 2 × 3 = 6? No.
- j = 4: 3 > 2 × 1 = 2? Yes! count = 1.
Step 3: Fix i = 2 (nums[2] = 2). Check all j > 2:
- j = 3: 2 > 2 × 3 = 6? No.
- j = 4: 2 > 2 × 1 = 2? No (2 is NOT strictly greater than 2).
- count stays 1.
Step 4: Fix i = 3 (nums[3] = 3). Check all j > 3:
- j = 4: 3 > 2 × 1 = 2? Yes! count = 2.
Step 5: i = 4 is the last element — no j exists beyond it.
Result: count = 2.
Brute Force — Checking All Pairs for Reverse Pairs — Watch how we systematically check every pair (i, j) with i < j to see if nums[i] > 2 * nums[j]. Most pairs fail the condition; we count only those that pass.
Algorithm
- Initialize a counter
count = 0. - For each index
ifrom0ton - 2:- For each index
jfromi + 1ton - 1:- If
nums[i] > 2 * nums[j], incrementcount.
- If
- For each index
- Return
count.
Important: When computing 2 * nums[j], use long (64-bit integer) to avoid integer overflow, since nums[j] can be up to 2^31 - 1.
Code
#include <vector>
using namespace std;
class Solution {
public:
int reversePairs(vector<int>& nums) {
int n = nums.size();
int count = 0;
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
if ((long long)nums[i] > 2LL * nums[j]) {
count++;
}
}
}
return count;
}
};class Solution:
def reversePairs(self, nums: list[int]) -> int:
n = len(nums)
count = 0
for i in range(n):
for j in range(i + 1, n):
if nums[i] > 2 * nums[j]:
count += 1
return countclass Solution {
public int reversePairs(int[] nums) {
int n = nums.length;
int count = 0;
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
if ((long) nums[i] > 2L * nums[j]) {
count++;
}
}
}
return count;
}
}Complexity Analysis
Time Complexity: O(n²)
The outer loop runs n times, and for each value of i, the inner loop runs up to n - i - 1 times. The total number of pair checks is n × (n - 1) / 2, which is O(n²). For n = 50,000 this means roughly 1.25 billion comparisons — far too slow.
Space Complexity: O(1)
We only use a single counter variable. No additional data structures are needed.
Why This Approach Is Not Efficient
With n up to 50,000, the brute force performs about 1.25 × 10^9 pair comparisons. This will almost certainly exceed the time limit on any online judge.
The core problem is that for each element, we are doing a linear scan of all elements to its right. We are not leveraging any structure or order within the array.
The key insight comes from a technique used in counting inversions: merge sort. During the merge step of merge sort, we have two sorted halves. Because both halves are sorted, we can count how many elements in the left half satisfy nums[i] > 2 * nums[j] for each element in the right half — not one-by-one, but in bulk. If nums[i] > 2 * nums[j], then all elements from index i to the end of the left half also satisfy the condition (since the left half is sorted in ascending order). This transforms the counting from O(n²) to O(n log n).
Optimal Approach - Modified Merge Sort
Intuition
This problem is a variation of the classic "count inversions" problem, but with the condition nums[i] > 2 * nums[j] instead of simply nums[i] > nums[j].
The idea is to use merge sort as a framework. Merge sort naturally divides the array into halves and processes them recursively. At each merge step, we have two sorted subarrays. Because both subarrays are sorted, we can efficiently count cross-pairs (pairs where one element is in the left half and the other is in the right half) using a two-pointer technique.
Here is the core insight: suppose the left half is sorted as [a₁, a₂, ..., aₘ] and the right half is sorted as [b₁, b₂, ...]. For a fixed bⱼ in the right half, we want the count of elements aᵢ in the left half where aᵢ > 2 * bⱼ. Because the left half is sorted, once we find the first aᵢ that exceeds 2 * bⱼ, all subsequent elements (aᵢ₊₁, aᵢ₊₂, ..., aₘ) will also exceed it. So we can add (m - i + 1) pairs in one step instead of checking each individually.
The algorithm has two phases at each merge step:
- Count phase: Use two pointers to count reverse pairs across the two sorted halves.
- Merge phase: Standard merge of the two sorted halves to maintain the sorted order for the next recursion level.
These two phases are done separately to avoid mixing up the counting logic with the reordering logic.

Step-by-Step Explanation
Let's trace through with nums = [1, 3, 2, 3, 1]. We will focus on the merge steps where counting happens.
Recursion splits the array:
- [1, 3, 2, 3, 1] → left = [1, 3, 2], right = [3, 1]
- [1, 3, 2] → left = [1, 3], right = [2]
- [1, 3] → left = [1], right = [3]
- [3, 1] → left = [3], right = [1]
Step 1: Merge [1] and [3] (left half of [1, 3, 2])
- Count phase: i=0, j=0. Is nums[i]=1 > 2*nums[j]=6? No. Move i. i exceeds mid. Count = 0.
- Merge phase: Merge to get [1, 3].
Step 2: Merge [1, 3] and [2] (forming sorted [1, 3, 2] → [1, 2, 3])
- Count phase: i=0, j=0. Is 1 > 22=4? No. Move i. Is 3 > 22=4? No. Move i. Count = 0.
- Merge phase: Merge to get [1, 2, 3].
Step 3: Merge [3] and [1] (right half [3, 1])
- Count phase: i=0, j=0. Is 3 > 2*1=2? Yes! Add (mid - i + 1) = (0 - 0 + 1) = 1. Move j. Count = 1.
- Merge phase: Merge to get [1, 3].
Step 4: Final merge of [1, 2, 3] and [1, 3]
- Count phase with two pointers on sorted halves:
- i=0, j=0: Is left[0]=1 > 2*right[0]=2? No. Move i.
- i=1, j=0: Is left[1]=2 > 2*right[0]=2? No. Move i.
- i=2, j=0: Is left[2]=3 > 2*right[0]=2? Yes! Add (mid - i + 1) = (2 - 2 + 1) = 1. Move j.
- i=2, j=1: Is left[2]=3 > 2*right[1]=6? No. Move i. i exceeds mid.
- Count from this merge = 1.
- Merge phase: Merge to get [1, 1, 2, 3, 3].
Total: 0 + 0 + 1 + 1 = 2 reverse pairs.
Modified Merge Sort — Counting Reverse Pairs — Watch the key merge step where we count reverse pairs between two sorted halves [1, 2, 3] and [1, 3] using two pointers, then merge them.
Algorithm
- Define a recursive function
mergeSort(nums, left, right)that returns the count of reverse pairs in the subarraynums[left..right]. - Base case: If
left >= right, return 0 (a single element has no pairs). - Divide: Compute
mid = (left + right) / 2. Recursively count pairs inmergeSort(nums, left, mid)andmergeSort(nums, mid+1, right). Sum the two counts. - Count cross-pairs: Use two pointers
i = leftandj = mid + 1. While both pointers are in range:- If
nums[i] <= 2 * nums[j], incrementi(current left element is too small). - Else, all elements from
itomidform reverse pairs withnums[j]. Add(mid - i + 1)to the count and incrementj.
- If
- Merge phase: Perform standard merge of the two sorted halves into a temporary array, then copy back to
nums. - Return the total count.
Critical detail: Use 64-bit integers (long long in C++, long in Java) when computing 2 * nums[j] to avoid integer overflow, since nums[j] can be as large as 2^31 - 1.
Code
#include <vector>
using namespace std;
class Solution {
public:
int reversePairs(vector<int>& nums) {
return mergeSort(nums, 0, nums.size() - 1);
}
private:
int mergeSort(vector<int>& nums, int left, int right) {
if (left >= right) return 0;
int mid = left + (right - left) / 2;
int count = mergeSort(nums, left, mid)
+ mergeSort(nums, mid + 1, right);
// Count cross reverse pairs
int j = mid + 1;
for (int i = left; i <= mid; i++) {
while (j <= right && (long long)nums[i] > 2LL * nums[j]) {
j++;
}
count += (j - (mid + 1));
}
// Standard merge
vector<int> temp;
int p1 = left, p2 = mid + 1;
while (p1 <= mid && p2 <= right) {
if (nums[p1] <= nums[p2]) {
temp.push_back(nums[p1++]);
} else {
temp.push_back(nums[p2++]);
}
}
while (p1 <= mid) temp.push_back(nums[p1++]);
while (p2 <= right) temp.push_back(nums[p2++]);
for (int i = left; i <= right; i++) {
nums[i] = temp[i - left];
}
return count;
}
};class Solution:
def reversePairs(self, nums: list[int]) -> int:
def merge_sort(left: int, right: int) -> int:
if left >= right:
return 0
mid = (left + right) // 2
count = merge_sort(left, mid) + merge_sort(mid + 1, right)
# Count cross reverse pairs
j = mid + 1
for i in range(left, mid + 1):
while j <= right and nums[i] > 2 * nums[j]:
j += 1
count += (j - (mid + 1))
# Standard merge
temp = []
p1, p2 = left, mid + 1
while p1 <= mid and p2 <= right:
if nums[p1] <= nums[p2]:
temp.append(nums[p1])
p1 += 1
else:
temp.append(nums[p2])
p2 += 1
temp.extend(nums[p1:mid + 1])
temp.extend(nums[p2:right + 1])
nums[left:right + 1] = temp
return count
return merge_sort(0, len(nums) - 1)class Solution {
public int reversePairs(int[] nums) {
return mergeSort(nums, 0, nums.length - 1);
}
private int mergeSort(int[] nums, int left, int right) {
if (left >= right) return 0;
int mid = left + (right - left) / 2;
int count = mergeSort(nums, left, mid)
+ mergeSort(nums, mid + 1, right);
// Count cross reverse pairs
int j = mid + 1;
for (int i = left; i <= mid; i++) {
while (j <= right && (long) nums[i] > 2L * nums[j]) {
j++;
}
count += (j - (mid + 1));
}
// Standard merge
int[] temp = new int[right - left + 1];
int p1 = left, p2 = mid + 1, k = 0;
while (p1 <= mid && p2 <= right) {
if (nums[p1] <= nums[p2]) {
temp[k++] = nums[p1++];
} else {
temp[k++] = nums[p2++];
}
}
while (p1 <= mid) temp[k++] = nums[p1++];
while (p2 <= right) temp[k++] = nums[p2++];
for (int i = left; i <= right; i++) {
nums[i] = temp[i - left];
}
return count;
}
}Complexity Analysis
Time Complexity: O(n log n)
Merge sort divides the array into log n levels. At each level, we process all n elements twice — once for counting reverse pairs and once for merging. Both the count phase and the merge phase use two-pointer techniques that run in O(n) at each level. Therefore the total time is O(n log n).
For n = 50,000, this is approximately 50,000 × 17 ≈ 850,000 operations — well within time limits.
Space Complexity: O(n)
We use a temporary array of up to n elements for the merge step at each recursion level. The recursion stack adds O(log n) depth. Since O(n) + O(log n) = O(n), the overall space complexity is O(n).