javaalgorithm

Find unique pairs


There is a list of numbers of size n, find the maximum count of the number of pairs such that it follows the below pattern:

2 * minimum(arr[i],arr[j]) <= maximum (arr[i], arr[j]), where [i,j] in range (0 to n)

The selected indices should be unique, it means if an index say 2 is used to form a pair say (2,5), we should not use the same index 2 to form another pair (2,7).

Example:
arr = [2, 5, 7, 6, 9, 8 , 4 , 2]
result = 3
Explanation:

Sort input = [2,2,4,5,6,7,8,9]
All possible pairs that can be formed are:
2 can form pairs with [4,5,6,7,8,9]
4 can form pairs with [8,9]
For 5, there is no matching pair that satisfies the condition.

We cannot pick the pair (2,4) because if 4 is already used we cannot form new pairs like (4,8) or (4,9)

Finally, we can form 3 maximum counts of pairs using distinct indices, One such possible pairs are (2,5), (7, 2), and (9, 4), so the answer is 3

Example:
arr = [2,1,2,4,1,4,1]
result = 3
Explanation:

Pairs are (2,1), (4,1), and (2,4), so the answer is 3

Constraints:
  • n is in the range 1 to n^5
  • each input item,is in range 1 to 10^9

I tried solving this using a TreeMap:

import java.util.*;
public class Main
{
    public static void main(String[] args) {
        System.out.println(solve(Arrays.asList(2, 5, 7, 6, 9, 8 , 4 , 2)));//3
        System.out.println(solve(Arrays.asList(2,1,2,4,1,4,1)));//3
    }
    
    static int solve(List<Integer> arr) {
        arr.sort(Comparator.reverseOrder());
        TreeMap<Integer, Integer> map = new TreeMap<>();
        for(int e : arr) map.put(e, map.getOrDefault(e,0)+1);
        int result = 0;
        for(int e : arr) {
            int min = 2 * e;
            if(map.get(e) == null) continue;
            Integer key = map.ceilingKey(min);
            if(key != null) {
                map.put(e,map.get(e)-1);
                if(map.get(e) <=0)map.remove(e);
                
                map.put(key,map.get(key)-1);
                if(map.get(key) <=0)map.remove(key);
                result++;
            }
        }
        return result;
    }
}

But for 2nd test case arr = [2,1,2,4,1,4,1], I am creating pairs in my code as (2,4), (2,4), so it is returning 2 instead of 3.

I tried greedy and 2 pointer approach but both are not working.

What is the correct approach for this problem?


Solution

  • Based on Matt's answer: Sort and then greedily try to pair right-half elements with left-half elements. O(n log n) for sorting and O(n) for the rest.

    static int solve(List<Integer> arr) {
        arr.sort(null);
        int i = 0, n = arr.size();
        for (int j = (n+1)/2; j < n; j++)
            if (2 * arr.get(i) <= arr.get(j))
                i++;
        return i;
    }
    

    Attempt This Online!