Nuts & Bolts (or Lock & Key) Problem

Last Updated : 19 Aug, 2026

Given a set of n nuts of different sizes and n bolts of different sizes. There is a one-one mapping between nuts and bolts. Match nuts and bolts efficiently. Comparison of a nut to another nut or a bolt to another bolt is not allowed. The elements in output should follow the following order: { !,#,$,%,&,*,?,@,^ }

Input: , nuts[] = {@, %, $, #, ^}, bolts[] = {%, @, #, $ ^}
Output: # $ % @ ^
Explanation: As per the order # should come first after that $ then % then @ and ^.

Input: nuts[] = {^, &, %, @, #, *, $, ?, !}, bolts[] = {?, #, @, %, &, *, $ ,^, !}
Output: ! # $ % & * ? @ ^
Explanation: We'll have to match first ! then # , $, %, &, *, @, ^, ? as per the required ordering.

Try It Yourself
redirect icon

Using Quick Sort Partitioning - O(n log n) Time and O(log n) Space

Quick sort is applied on nuts and bolts simultaneously — the last bolt acts as a pivot to partition nuts, then the matched nut partitions bolts. This cross-partitioning repeats recursively on left and right sub-arrays until all pairs are matched.

Here how it works:
1. Pick the last element of bolts[] as pivot and partition the nuts[] array around it, returning index i.
2. Use nuts[i] as the next pivot to partition the bolts[] array. Each partition runs in O(n).
3. Recur on the left and right sub-arrays of both nuts[] and bolts[] until all pairs are matched.

C++
#include <iostream>
#include <vector>
using namespace std;

// Partition function
int partition(vector<char> &arr, int low, int high, char pivot) {
    int i = low;

    for (int j = low; j < high; j++) {
        if (arr[j] < pivot) {
            swap(arr[i], arr[j]);
            i++;
        }
        else if (arr[j] == pivot) {
            swap(arr[j], arr[high]);
            
            // recheck swapped element
            j--;
        }
    }

    swap(arr[i], arr[high]);
    return i;
}

// Helper recursive function
void solve(vector<char> &nuts, vector<char> &bolts, int low, int high) {
    if (low < high) {
        int pivot = partition(nuts, low, high, bolts[high]);
        partition(bolts, low, high, nuts[pivot]);

        solve(nuts, bolts, low, pivot - 1);
        solve(nuts, bolts, pivot + 1, high);
    }
}

// Required function
void matchPairs(vector<char> &nuts, vector<char> &bolts) {
    solve(nuts, bolts, 0, nuts.size() - 1);
}

// Driver code
int main() {
    vector<char> nuts = {'@', '#', '$', '%', '^', '&'};
    vector<char> bolts = {'$', '%', '&', '^', '@', '#'};

    matchPairs(nuts, bolts);


    for (char c : bolts) cout << c << " ";

    return 0;
}
C
#include <stdio.h>

void swap(char *a, char *b) {
    char temp = *a;
    *a = *b;
    *b = temp;
}

// Partition function (same logic as QuickSort)
int partition(char arr[], int low, int high, char pivot) {
    int i = low;

    for (int j = low; j < high; j++) {

        // If element is smaller than pivot
        if (arr[j] < pivot) {
            swap(&arr[i], &arr[j]);
            i++;
        }

        // If element equals pivot → move to end
        else if (arr[j] == pivot) {
            swap(&arr[j], &arr[high]);
            j--;  // recheck swapped element
        }
    }

    // Place pivot at correct position
    swap(&arr[i], &arr[high]);
    return i;
}

// Recursive helper function
void solve(char nuts[], char bolts[], int low, int high) {
    if (low < high) {

        // Use last bolt as pivot for nuts
        int pivot = partition(nuts, low, high, bolts[high]);

        // Use matched nut as pivot for bolts
        partition(bolts, low, high, nuts[pivot]);

        // Recur for left and right parts
        solve(nuts, bolts, low, pivot - 1);
        solve(nuts, bolts, pivot + 1, high);
    }
}

// Main function to match pairs
void matchPairs(char nuts[], char bolts[], int n) {
    solve(nuts, bolts, 0, n - 1);
}

// Driver code
int main() {
    char nuts[]  = {'@', '#', '$', '%', '^', '&'};
    char bolts[] = {'$', '%', '&', '^', '@', '#'};
    int n = sizeof(nuts) / sizeof(nuts[0]);

    matchPairs(nuts, bolts, n);

    // Print result
    for (int i = 0; i < n; i++) {
        printf("%c ", bolts[i]);
    }

    return 0;
}
Java
import java.util.*;

class GFG {

    // Partition function similar to quicksort
    static int partition(char[] arr, int low, int high, char pivot) {
        int i = low;

        for (int j = low; j < high; j++) {

            // If current element is smaller than pivot
            if (arr[j] < pivot) {
                char temp = arr[i];
                arr[i] = arr[j];
                arr[j] = temp;
                i++;
            }

            // If element equals pivot → move it to end
            else if (arr[j] == pivot) {
                char temp = arr[j];
                arr[j] = arr[high];
                arr[high] = temp;

                j--; // recheck swapped element
            }
        }

        // Place pivot at correct position
        char temp = arr[i];
        arr[i] = arr[high];
        arr[high] = temp;

        return i;
    }

    // Recursive helper
    static void solve(char[] nuts, char[] bolts, int low, int high) {
        if (low < high) {

            // Use last bolt as pivot for nuts
            int pivot = partition(nuts, low, high, bolts[high]);

            // Use matched nut as pivot for bolts
            partition(bolts, low, high, nuts[pivot]);

            // Recur left and right
            solve(nuts, bolts, low, pivot - 1);
            solve(nuts, bolts, pivot + 1, high);
        }
    }

    static void matchPairs(char[] nuts, char[] bolts) {
        solve(nuts, bolts, 0, nuts.length - 1);
    }

    public static void main(String[] args) {
        char[] nuts = {'@', '#', '$', '%', '^', '&'};
        char[] bolts = {'$', '%', '&', '^', '@', '#'};

        matchPairs(nuts, bolts);

        for (char c : bolts) {
            System.out.print(c + " ");
        }
    }
}
Python
# Partition function
def partition(arr, low, high, pivot):
    i = low
    j = low

    while j < high:
        if arr[j] < pivot:
            arr[i], arr[j] = arr[j], arr[i]
            i += 1
            j += 1

        elif arr[j] == pivot:
            arr[j], arr[high] = arr[high], arr[j]
            # Do not increment j.
            # Recheck the newly swapped element.

        else:
            j += 1

    arr[i], arr[high] = arr[high], arr[i]
    return i


# Helper recursive function
def solve(nuts, bolts, low, high):
    if low >= high:
        return

    # Use a bolt as pivot to partition nuts
    pivot = partition(nuts, low, high, bolts[high])

    # Use the matched nut as pivot to partition bolts
    partition(bolts, low, high, nuts[pivot])

    solve(nuts, bolts, low, pivot - 1)
    solve(nuts, bolts, pivot + 1, high)


# Required function
def matchPairs(nuts, bolts):
    solve(nuts, bolts, 0, len(nuts) - 1)


# Driver code
nuts = ['@', '#', '$', '%', '^', '&']
bolts = ['$', '%', '&', '^', '@', '#']

matchPairs(nuts, bolts)

for c in bolts:
    print(c, end=" ")
C#
using System;

class GFG {

    // Partition function
    static int Partition(char[] arr, int low, int high, char pivot) {
        int i = low;

        for (int j = low; j < high; j++) {

            if (arr[j] < pivot) {
                char temp = arr[i];
                arr[i] = arr[j];
                arr[j] = temp;
                i++;
            }
            else if (arr[j] == pivot) {
                char temp = arr[j];
                arr[j] = arr[high];
                arr[high] = temp;

                j--; // recheck
            }
        }

        char t = arr[i];
        arr[i] = arr[high];
        arr[high] = t;

        return i;
    }

    // Recursive function
    static void Solve(char[] nuts, char[] bolts, int low, int high) {
        if (low < high) {
            int pivot = Partition(nuts, low, high, bolts[high]);
            Partition(bolts, low, high, nuts[pivot]);

            Solve(nuts, bolts, low, pivot - 1);
            Solve(nuts, bolts, pivot + 1, high);
        }
    }

    static void matchPairs(char[] nuts, char[] bolts) {
        Solve(nuts, bolts, 0, nuts.Length - 1);
    }

    static void Main() {
        char[] nuts = { '@', '#', '$', '%', '^', '&' };
        char[] bolts = { '$', '%', '&', '^', '@', '#' };

        matchPairs(nuts, bolts);

        foreach (char c in bolts) {
            Console.Write(c + " ");
        }
    }
}
JavaScript
// Partition function
function partition(arr, low, high, pivot) {
    let i = low;

    for (let j = low; j < high; j++) {

        // Smaller than pivot
        if (arr[j] < pivot) {
            [arr[i], arr[j]] = [arr[j], arr[i]];
            i++;
        }

        // Equal to pivot → move to end
        else if (arr[j] === pivot) {
            [arr[j], arr[high]] = [arr[high], arr[j]];
            j--; // recheck
        }
    }

    // Place pivot correctly
    [arr[i], arr[high]] = [arr[high], arr[i]];
    return i;
}

// Recursive helper
function solve(nuts, bolts, low, high) {
    if (low < high) {
        let pivot = partition(nuts, low, high, bolts[high]);
        partition(bolts, low, high, nuts[pivot]);

        solve(nuts, bolts, low, pivot - 1);
        solve(nuts, bolts, pivot + 1, high);
    }
}

// Main function
function matchPairs(nuts, bolts) {
    solve(nuts, bolts, 0, nuts.length - 1);
}

// Driver
let nuts = ['@', '#', '$', '%', '^', '&'];
let bolts = ['$', '%', '&', '^', '@', '#'];

matchPairs(nuts, bolts);

console.log(bolts.join(" "));

Output
# $ % & @ ^ 

Why we cannot use Hashing to solve this ?

If we use hashing, then we will have to compare nuts with nuts or bolts with bolts either while inserting into the hash and/or while printing the result in sorted order.


Comment