NP-Completeness Explained: P, NP, and Why Some Problems Resist Efficient Solutions

Some problems have resisted every attempt at an efficient algorithm for decades, yet no one has proven an efficient solution is impossible. This comprehensive guide explains the classes P and NP, the concept of polynomial-time reductions used to compare problem difficulty, and how proving a problem NP-complete provides strong evidence, though not proof, that no efficient algorithm exists.

NP-CompletenessP versus NPPolynomial-Time Reduction

~5 min read · Updated Sep 7, 2026

Why Some Problems Have No Known Efficient Algorithm

Every algorithm covered so far in this series — sorting, shortest paths, minimum spanning trees — runs in polynomial time, meaning its running time is bounded by some polynomial function of the input size. But a large and practically important class of problems has no known polynomial-time algorithm, despite decades of effort by researchers worldwide. This article explains the theory that classifies these problems and explains why their apparent difficulty is not simply a matter of insufficient cleverness.

The Complexity Class P

P is the class of decision problems (problems with a yes/no answer) solvable by a deterministic algorithm in polynomial time. Every algorithm discussed throughout this series — sorting in O(n log n), shortest paths in O(VE) or better, minimum spanning trees in O(E log V) — solves a problem in P. Problems in P are generally considered Tractable, meaning practically solvable even for large inputs.

The Complexity Class NP

NP stands for "Nondeterministic Polynomial time," but is more intuitively understood through the concept of Verification: a problem is in NP if, given a proposed solution (called a Certificate), that solution can be verified as correct in polynomial time, even if finding the solution in the first place might be much harder.

Example: the Hamiltonian cycle problem
(does a graph contain a cycle visiting every vertex exactly once?)

Finding such a cycle from scratch might require
checking an exponential number of possible orderings

But VERIFYING a proposed cycle is trivial:
just check that it visits every vertex exactly once
and that consecutive vertices in the proposed cycle
are actually connected by edges — this takes only O(V) time

Since P problems can obviously be verified in polynomial time (simply re-solve them from scratch, which is already fast), every problem in P is also in NP, giving the relationship P ⊆ NP. The famous open question, P vs. NP, asks whether this containment is strict — whether there exist problems in NP that are not in P, meaning verifiable quickly but not solvable quickly.

Reductions: Comparing Problem Difficulty

A Polynomial-Time Reduction from problem A to problem B is a polynomial-time algorithm that transforms any instance of A into an equivalent instance of B, such that the answer to the transformed instance of B is the same as the answer to the original instance of A.

If A reduces to B in polynomial time (written A ≤ₚ B),
this means: if B can be solved in polynomial time,
then A can also be solved in polynomial time
(simply reduce A to B, then solve B)

Equivalently: if A cannot be solved in polynomial time,
then B cannot be solved in polynomial time either
(otherwise A could be solved via the reduction)

Reductions are the fundamental tool for comparing the relative difficulty of problems: a reduction from A to B shows that B is "at least as hard" as A, since any algorithm for B immediately yields an algorithm for A.

NP-Hardness and NP-Completeness

A problem H is NP-Hard if every problem in NP can be reduced to it in polynomial time — meaning H is at least as hard as every problem in NP. A problem is NP-Complete if it is both NP-hard and itself a member of NP.

NP-Complete problems are, informally, the "hardest"
problems in NP: if any single NP-complete problem
could be solved in polynomial time, then EVERY
problem in NP could also be solved in polynomial time,
proving P = NP

This is why NP-completeness is such a significant classification: it connects an individual problem's difficulty to the resolution of the entire P versus NP question, one of the most important open problems in all of computer science and mathematics.

The Cook-Levin Theorem: The First NP-Complete Problem

Establishing that any problem is NP-complete initially seems circular — how can a problem be shown at least as hard as "every problem in NP" without checking infinitely many problems individually? The breakthrough Cook-Levin Theorem resolved this by directly proving that SAT (the Boolean satisfiability problem: given a Boolean formula, does some assignment of true/false values to its variables make the whole formula true?) is NP-complete, using a direct construction based on the formal definition of a Turing machine.

Building the Web of NP-Complete Problems Through Reductions

Once one problem is known to be NP-complete, proving a new problem X is NP-complete no longer requires this fundamental construction. Instead, it only requires two steps.

To prove problem X is NP-complete:

Step 1: Show X is in NP
        (a proposed solution to X can be verified in polynomial time)

Step 2: Show some known NP-complete problem Y
        reduces to X in polynomial time (Y ≤ₚ X)
        (this shows X is at least as hard as Y,

Written & researched by Dr. Shahin Siami

Related Articles

Number-Theoretic Algorithms: GCD, Modular Exponentiation, and RSA

Modern cryptography and countless algorithmic applications rely on a handful of elegant number-theoretic algorithms. This comprehensive guide covers Euclid's algorithm for computing the greatest common divisor, fast modular exponentiation for efficiently computing large powers, and the mathematical foundation of RSA encryption, one of the most widely deployed cryptographic systems in the world.

Continue

Computational Geometry Basics: Orientation, Line Intersection, and Convex Hull

Geometric algorithms solve problems involving points, lines, and shapes, appearing in computer graphics, robotics path planning, and geographic information systems. This comprehensive guide covers the cross-product-based orientation test that underlies nearly every geometric algorithm, segment intersection detection built on that test, and Graham's scan algorithm for computing the convex hull of a set of points.

Continue

String Matching Algorithms: Naive Search, Rabin-Karp, and Beyond

Searching for a pattern within a larger text is one of the most common operations in computing, from text editors to DNA sequence analysis. This comprehensive guide covers the naive string-matching algorithm and its quadratic worst case, then explains the Rabin-Karp algorithm's clever use of hashing to achieve fast average-case performance, including how it handles hash collisions correctly.

Continue

Approximation Algorithms: Getting Provably Close to Optimal for Hard Problems

When a problem is proven NP-complete, an exact efficient solution is unlikely to exist, but that does not mean giving up on the problem entirely. This comprehensive guide explains approximation algorithms, which sacrifice guaranteed optimality for guaranteed efficiency, covering the vertex cover and traveling salesman problems as classic examples with provable approximation ratios.

Continue

Maximum Flow: Ford-Fulkerson and the Min-Cut Max-Flow Theorem

Maximum flow problems model the largest possible throughput through a network with capacity-limited connections, from water pipes to data networks. This comprehensive guide introduces flow networks, walks through the Ford-Fulkerson method for finding maximum flow using augmenting paths, and explains the elegant min-cut max-flow theorem that connects two seemingly different problems into one.

Continue

The Floyd-Warshall Algorithm: Finding Shortest Paths Between Every Pair of Vertices

Sometimes an application needs the shortest distance between every possible pair of vertices, not just from a single source. This comprehensive guide explains the all-pairs shortest paths problem, derives the elegant dynamic programming recurrence behind the Floyd-Warshall algorithm, and compares its performance against repeatedly running single-source algorithms.

Continue