DEV Community

Jaspreet singh
Jaspreet singh

Posted on

Reverse Pairs

Given an integer array nums, return the number of reverse pairs.

A reverse pair is defined as:

i < j && nums[i] > 2 * nums[j]
Enter fullscreen mode Exit fullscreen mode

Brute Force Approach

Intuition

Generate every possible pair (i, j) where i < j and check whether:

nums[i] > 2 * nums[j]
Enter fullscreen mode Exit fullscreen mode

If the condition is true, increment the count.

Java

class Solution {
    public int reversePairs(int[] nums) {

        int count = 0;

        for (int i = 0; i < nums.length; i++) {
            for (int j = i + 1; j < nums.length; j++) {

                if ((long) nums[i] > 2L * nums[j]) {
                    count++;
                }
            }
        }

        return count;
    }
}
Enter fullscreen mode Exit fullscreen mode

Complexity

  • Time: O(N²)
  • Space: O(1)

Why Think About Merge Sort?

The brute force solution checks every pair individually.

Can we count multiple valid pairs together?

The answer is yes, if the array is sorted.

Merge Sort naturally divides the array into sorted halves, which helps us efficiently count reverse pairs during the merge step.


Key Observation

Suppose after recursion we have:

Left  = [3, 5]
Right = [1, 2]
Enter fullscreen mode Exit fullscreen mode

Both halves are already sorted.

We need to count:

left[i] > 2 * right[j]
Enter fullscreen mode Exit fullscreen mode

For every element in the left half.


The Magic of Sorting

Consider:

5 > 2 * 1   
5 > 2 * 2   
Enter fullscreen mode Exit fullscreen mode

Since the right half is sorted:

[1, 2]
Enter fullscreen mode Exit fullscreen mode

once a value satisfies the condition, all smaller values before it will also satisfy it.

This allows us to use a moving pointer and count multiple pairs at once instead of checking every combination.


Dry Run

Left  = [3, 5]
Right = [1, 2]
Enter fullscreen mode Exit fullscreen mode

Start:

j = 0
Enter fullscreen mode Exit fullscreen mode

For 3

3 > 2 * 1
3 > 2
Enter fullscreen mode Exit fullscreen mode

Valid.

Move j.

3 > 2 * 2
3 > 4
Enter fullscreen mode Exit fullscreen mode

False.

Pairs contributed:

1
Enter fullscreen mode Exit fullscreen mode

For 5

Continue from current j.

5 > 2 * 2
5 > 4
Enter fullscreen mode Exit fullscreen mode

Valid.

Move j.

Pairs contributed:

2
Enter fullscreen mode Exit fullscreen mode

Total reverse pairs:

3
Enter fullscreen mode Exit fullscreen mode

Which are:

(3,1)
(5,1)
(5,2)
Enter fullscreen mode Exit fullscreen mode

Merge Sort Strategy

For every merge step:

Count pairs in left half
+
Count pairs in right half
+
Count cross pairs
Enter fullscreen mode Exit fullscreen mode

The important detail:

Count first
Then merge
Enter fullscreen mode Exit fullscreen mode

Because counting requires two separate sorted halves.

Once merged, that boundary disappears.


Optimal Solution

Intuition

While merging two sorted halves:

  • Use a pointer on the right half.
  • For every element in the left half, count how many elements satisfy:
nums[i] > 2 * nums[j]
Enter fullscreen mode Exit fullscreen mode

Since both halves are sorted, the pointer never moves backward.

This allows counting all cross pairs in linear time.

Java

class Solution {

    public int reversePairs(int[] nums) {
        return mergeSort(nums, 0, nums.length - 1);
    }

    private int mergeSort(int[] nums, int low, int high) {

        if (low >= high) return 0;

        int mid = low + (high - low) / 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;
    }

    private int countPairs(int[] nums, int low, int mid, int high) {

        int count = 0;
        int right = mid + 1;

        for (int i = low; i <= mid; i++) {

            while (right <= high &&
                   (long) nums[i] > 2L * nums[right]) {
                right++;
            }

            count += right - (mid + 1);
        }

        return count;
    }

    private void merge(int[] nums, int low, int mid, int high) {

        List<Integer> temp = new ArrayList<>();

        int left = low;
        int right = mid + 1;

        while (left <= mid && right <= high) {

            if (nums[left] <= nums[right]) {
                temp.add(nums[left++]);
            } else {
                temp.add(nums[right++]);
            }
        }

        while (left <= mid) {
            temp.add(nums[left++]);
        }

        while (right <= high) {
            temp.add(nums[right++]);
        }

        for (int i = low; i <= high; i++) {
            nums[i] = temp.get(i - low);
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Complexity

  • Time: O(N log N)
  • Space: O(N)

Takeaway

Whenever a problem asks you to count pairs:

i < j
Enter fullscreen mode Exit fullscreen mode

and the condition involves comparing elements from two positions, ask yourself:

Can sorting help me count multiple pairs together?

If the answer is yes, Merge Sort is often the hidden optimization.

Reverse Pairs is a classic example where sorting transforms an O(N²) brute force solution into an O(N log N) solution.

Top comments (0)