Suppose we are given n red and n blue water jugs, all of different shapes and sizes. All red jugs hold different amounts of water, as do the blue ones. Moreover, there is a blue jug for every red jug that holds the same amount of water and vice versa. The task is to efficiently group the jugs into pairs of red and blue jugs that hold the same amount of water. (Problem Source: CLRS)

A simple solution to group the jugs into pairs is to compare a red jug with each blue jug. Once we get the matching pair, group that pair, and repeat for the next red jug. This algorithm can be easily implemented, but it will perform at most n2 comparisons.

 
We can do better by using a randomized algorithm where the expected number of comparisons is n.log(n). The idea is analogous to the randomized Quicksort algorithm.

  • Randomly pick a jug from either red or blue jugs.
  • Partition the red jugs around the chosen jug such that it will be divided into two groups – red jugs smaller than the selected jug and those which are larger than the selected jug.
  • Once the red jugs have been divided, partition the blue jugs similarly – those which are smaller and those which are larger than the chosen jug.
  • Once the red and blue jugs are divided into two groups, repeat the process for the group of red and blue jugs that are smaller and larger than the chosen jug.

The expected number of comparisons performed by the above algorithm is the same as that of a randomized Quicksort algorithm, i.e., n.log(n) comparisons for n items. In the worst-case, the largest jug gets picked every time, which results in n2 comparisons.

 
Following is the implementation in C++, Java, and Python based on the above idea:

C++


Download  Run Code

Output:

Red jugs: 2 3 6 7 8
Blue jugs: 2 3 6 7 8

Java


Download  Run Code

Output:

Red jugs: [2, 3, 6, 7, 8]
Blue jugs: [2, 3, 6, 7, 8]

Python


Download  Run Code

Output:

Red jugs: [2, 3, 6, 7, 8]
Blue jugs: [2, 3, 6, 7, 8]

The time complexity of the above algorithm is the same as that of Quicksort, i.e., O(n.log(n)). The auxiliary space required by the algorithm is O(n) for the call stack.

 
There are several other variations of this problem which can be solved similarly:

  1. Nuts & Bolts Problem: Given n nuts and n bolts of different shapes and sizes. The task is to match nuts with bolts, provided that a specific bolt can open each nut.
  2. Lock & Key Problem: Given a box of n locks and n keys where each lock can be opened by only a specific key in the box. The task is to match locks with their keys.