Grover’s algorithm, discovered by Lov Grover in 1996, searches an unsorted database of $N$ items in $O(\sqrt{N})$ time — a quadratic speedup over the classical $O(N)$.

The Problem

Given a function $f: \{0, 1, \ldots, N-1\} \to \{0, 1\}$ that returns 1 for exactly one “marked” item $w$, find $w$.

Classically, this requires $O(N)$ function evaluations. Grover’s algorithm requires only $O(\sqrt{N})$.

The Algorithm

Grover’s algorithm has three main steps, repeated approximately $\frac{\pi}{4}\sqrt{N}$ times:

1. Initialize in Uniform Superposition

$$|s\rangle = H^{\otimes n}|0\rangle^{\otimes n} = \frac{1}{\sqrt{N}} \sum_{x=0}^{N-1} |x\rangle$$

2. Oracle Query

The oracle flips the phase of the marked item:

$$O|x\rangle = \begin{cases} -|x\rangle & \text{if } x = w \\ |x\rangle & \text{otherwise} \end{cases}$$

Mathematically: $O = I - 2|w\rangle\langle w|$

3. Diffusion Operator (Amplitude Amplification)

$$D = 2|s\rangle\langle s| - I$$

This reflects all amplitudes about their mean, amplifying the marked item’s amplitude while suppressing others.

Qiskit Implementation

from qiskit import QuantumCircuit
from qiskit.quantum_info import Statevector
import numpy as np

def grovers_search(n_qubits=3, target=5):
    """
    Grover's algorithm for searching n_qubits.
    target: the integer to search for (0 to 2^n - 1)
    """
    N = 2**n_qubits
    iterations = int(np.pi / 4 * np.sqrt(N))

    qc = QuantumCircuit(n_qubits)

    # Step 1: Initialize superposition
    qc.h(range(n_qubits))

    for _ in range(iterations):
        # Step 2: Oracle — mark the target
        target_bits = format(target, f'0{n_qubits}b')
        for i, bit in enumerate(reversed(target_bits)):
            if bit == '0':
                qc.x(i)
        qc.h(n_qubits - 1)
        qc.mcx(list(range(n_qubits - 1)), n_qubits - 1)
        qc.h(n_qubits - 1)
        for i, bit in enumerate(reversed(target_bits)):
            if bit == '0':
                qc.x(i)

        # Step 3: Diffusion operator
        qc.h(range(n_qubits))
        qc.x(range(n_qubits))
        qc.h(n_qubits - 1)
        qc.mcx(list(range(n_qubits - 1)), n_qubits - 1)
        qc.h(n_qubits - 1)
        qc.x(range(n_qubits))
        qc.h(range(n_qubits))

    return qc

circuit = grovers_search(n_qubits=3, target=5)
sv = Statevector.from_instruction(circuit)
probs = sv.probabilities()
print(f"Probability of finding target |101⟩: {probs[5]:.4f}")

Why Only Quadratic?

It has been proven (by Bennett, Bernstein, Brassard, and Vazirani) that Grover’s algorithm is optimal — no quantum algorithm can search an unstructured database faster than $O(\sqrt{N})$. This is significant because it shows that quantum computers do not provide exponential speedups for all problems.

Applications

Despite being “only” quadratic, the speedup is transformative for:

  • Cryptography: Grover’s algorithm halves the effective key length of symmetric ciphers (AES-256 becomes AES-128 security)
  • Optimization: Amplitude amplification techniques extend to constraint satisfaction
  • Machine Learning: Speeding up nearest-neighbor search in high-dimensional spaces