What you'll learn
- Quick answer
- What P and NP actually mean
- The verify-vs-solve asymmetry, with real numbers
- What NP-complete means, and why it matters to you
- A small, honest NP-complete example end to end
- So, is P equal to NP?
- What to actually do about it as a working developer
- Common misconceptions worth clearing up
- FAQ
Quick Answer
P is the set of problems a computer can solve in polynomial time. NP is the set of problems where, if someone hands you a proposed solution, you can check it's correct in polynomial time, even if finding that solution yourself might take far longer. Whether P actually equals NP, whether every easy-to-check problem is secretly also easy-to-solve, is one of the biggest unsolved questions in computer science, and most researchers believe the answer is no.
What P and NP actually mean
P stands for "polynomial time". A problem is in P if there's an algorithm that solves it in time bounded by some polynomial in the input size, n, n^2, n^3, and so on, as opposed to exponential time (2^n) or worse. Sorting a list, searching a sorted array, finding the shortest path in a graph with Dijkstra's algorithm, these are all in P. In practice, "in P" is a reasonable stand-in for "efficiently solvable", though that's a simplification worth being honest about (an algorithm that runs in n^100 time is technically polynomial and practically useless; this is a known, acknowledged gap in using P as a proxy for "fast").
NP stands for "nondeterministic polynomial time", which is a historically-loaded name that confuses more people than it helps. The far more useful way to think about it: a problem is in NP if, given a proposed solution (a "certificate"), you can verify whether it's correct in polynomial time, even if you have no idea how to efficiently find that solution in the first place.
Take Sudoku as a concrete example. If someone hands you a completed Sudoku grid, checking whether it's a valid solution is fast and mechanical, scan every row, column, and box for duplicates. That's the NP part: verification is cheap. But generating a solution from a half-empty puzzle can require real search, there's no known shortcut that always avoids trying out possibilities. That gap, between "cheap to check" and "no known cheap way to find", is the entire subject of this article.
Every problem in P is also in NP (if you can solve it efficiently, you can trivially also verify a given answer efficiently, just solve it yourself and compare). The open question is the reverse direction: is every problem in NP secretly also in P? Is there always, eventually, some clever polynomial algorithm waiting to be discovered for every one of these problems, or are some of them fundamentally, provably harder to solve than to check?
The verify-vs-solve asymmetry, with real numbers
Subset sum is a classic NP problem: given a list of numbers and a target, does some subset of the numbers add up exactly to the target? It's in NP because if someone hands you a candidate subset, checking whether it sums to the target takes one pass through that subset, straightforwardly fast regardless of how large the full list is.
Finding that subset yourself, without being handed one, is a different story. The only known general-purpose approach is some form of search through the possibilities, and the full search space for a list of n numbers is every one of its 2^n subsets. I ran an exhaustive version of this search (checking every single subset, no early exit, no shortcuts) against lists of genuinely increasing size, and timed both the search and a separate verification of the found answer:
def brute_force_subset_sum_exhaustive(nums, target):
"""Enumerate ALL 2^n subsets (no early exit) to show the true
exponential cost of searching for a solution."""
n = len(nums)
count_checked = 0
found = None
for mask in range(1 << n):
subset = [nums[i] for i in range(n) if mask & (1 << i)]
count_checked += 1
if sum(subset) == target and found is None:
found = subset
return found, count_checked
def verify_subset_sum(nums, target, candidate_subset):
"""Verifying a PROPOSED answer is fast, O(n). This is the
'easy to check' half of the definition of NP."""
return sum(candidate_subset) == targetReal measured output, run on an ordinary laptop:
n subsets checked (2^n) search_time verify_time
12 4,096 0.011s 0.0052ms valid=True
16 65,536 0.238s 0.0028ms valid=True
18 262,144 0.594s 0.0022ms valid=True
20 1,048,576 3.247s 0.0030ms valid=True
21 2,097,152 7.796s 0.0021ms valid=True
22 4,194,304 16.194s 0.0029ms valid=TrueEach single increase in n roughly doubles the search time, exactly what 2^n growth predicts, going from 11 milliseconds at n=12 to over 16 seconds at n=22, a roughly 1,500x slowdown for an input only 10 items larger. Meanwhile, verification time for a given candidate subset stays flat at a few thousandths of a millisecond throughout, because verification is a single linear pass regardless of how large the search space behind it was. Extrapolate this honestly: by around n=40, even this exhaustive brute force would take on the order of days, and by n=60, centuries. That's not a performance bug to optimise away, it's the actual, structural shape of the problem.
(To be precise about subset sum specifically: this exhaustive 2^n search is a worst-case illustration, not the best known algorithm. A dynamic-programming approach can solve subset sum in time proportional to n times the target sum, which is "pseudo-polynomial", fast when the target sum is small, but still exponential in the number of bits needed to represent a very large target sum. The best known worst-case algorithms, using a meet-in-the-middle technique, get this down to roughly O(2^(n/2)), still exponential, just with a smaller exponent. No known algorithm solves the general case in time polynomial in n and the bit-length of the numbers involved, and subset sum is NP-complete, so finding one would resolve P vs NP for every NP-complete problem at once.)
What NP-complete means, and why it matters to you
Not every problem in NP is equally hard. Some, like checking if a number is prime, were long suspected to secretly be in P and were eventually proven to be (the AKS primality test, published in 2002, runs in polynomial time). Others sit in a special category called NP-complete: these are the hardest problems in NP, in a very specific, formal sense.
A problem is NP-complete if it's in NP, and every other problem in NP can be transformed into it using only a polynomial-time transformation (this is called a polynomial-time reduction). The consequence is striking: if you ever found a genuine polynomial-time algorithm for even one NP-complete problem, you could use that same transformation trick to solve every problem in NP in polynomial time, because you could rewrite any of them into that one solved problem first. That's exactly what "P = NP" would mean in practice: not a narrow technical curiosity, but every problem currently believed to require exponential search suddenly becoming efficiently solvable, all at once, through this web of reductions.
The first problem proven NP-complete was Boolean satisfiability (SAT), checking whether some assignment of true/false values to variables makes a given logical formula true. Stephen Cook proved this in 1971 (with Leonid Levin independently reaching closely related results around the same time, which is why it's often called the Cook-Levin theorem). The following year, Richard Karp showed 21 other well-known problems, including subset sum, the travelling salesman problem, and graph colouring, were also NP-complete, by reducing each of them to SAT or to each other. Thousands more have since joined that list.
Why this matters practically: if you're ever asked to solve a scheduling problem, a resource-allocation problem, or a route-optimisation problem at work, and it feels suspiciously hard no matter how you approach it, there's a real chance it's a disguised version of a known NP-complete problem. Recognising that early changes your entire strategy, instead of hunting for an exact, fast, general algorithm that almost certainly doesn't exist, you look for approximations, heuristics, or ways to restrict the problem's size or structure to something tractable.
A small, honest NP-complete example end to end
To ground this in something concrete rather than abstract, here's the actual reasoning the subset sum demo above relies on, laid out explicitly: subset sum is in NP because, given a candidate subset, checking its sum against the target is a single O(n) pass, no search involved. It's NP-complete because Richard Karp's original 1972 paper showed it can be reduced from related combinatorial covering problems in the same hardness class as SAT.
This has a very concrete consequence for anyone writing code against subset-sum-shaped problems (and they show up more often than the textbook name suggests, inventory matching against a target weight, selecting a combination of investments that hits a specific return, picking a subset of tasks that exactly fills a time budget): there is no known algorithm that solves the general case efficiently for large inputs, and most computer scientists believe, though cannot yet prove, that none exists. What you actually want to do in production is usually one of: restrict the input size (brute force is genuinely fine for n under roughly 20-25, as the measured timings above show directly), use the pseudo-polynomial dynamic-programming approach when the target sum is bounded and reasonably small, or accept an approximate answer using a greedy or randomized heuristic when exactness isn't strictly required.
This same reasoning pattern, identify the certificate, show verification is fast, then find or cite a reduction from a known NP-complete problem, is exactly the template used to classify virtually every NP-complete problem you'll encounter by name: the travelling salesman problem (certificate: a specific tour; verify its total length is under some bound), graph colouring (certificate: an assignment of colours to vertices; verify no edge connects two same-coloured vertices), and the knapsack problem (certificate: a selection of items; verify total weight and value against the constraints). Once you've internalised this pattern on one example end to end, as this article did with subset sum, recognising the shape in a new, unfamiliar problem becomes a matter of asking the same three questions rather than starting from scratch each time.
So, is P equal to NP?
Nobody knows. This is one of the seven "Millennium Prize Problems" named by the Clay Mathematics Institute in 2000, each carrying a $1,000,000 prize for a correct proof, and as of today it remains unsolved, alongside the Riemann Hypothesis (one other Millennium Prize problem, the Poincare conjecture, has been solved, by Grigori Perelman in 2003).
The overwhelming majority of computer scientists believe P does not equal NP, that there genuinely are problems which are fundamentally harder to solve than to check. The intuition is straightforward: decades of serious effort by extremely capable people have failed to find a polynomial algorithm for any NP-complete problem, across thousands of different problems from wildly different domains (logic, graphs, scheduling, number theory), and it would be a strange coincidence for every single one of them to be secretly easy while nobody's found the trick in over fifty years. But "nobody has found one" and "none exists" are different claims, and only a formal proof closes that gap. That gap is precisely what the prize money is for.
If P were somehow proven equal to NP (almost nobody expects this, but it hasn't been ruled out), the consequences would be enormous and immediate: most modern encryption relies on certain problems, like factoring large numbers, being hard to solve but easy to verify, and while factoring itself isn't known to be NP-complete, a genuinely general P=NP proof with a practical, efficient algorithm behind it would likely upend cryptography as it's currently practiced. It would also mean every NP-complete optimisation problem industries currently approximate, scheduling, logistics, chip design layout, could in principle be solved exactly and efficiently.
It's also worth noting what a proof in either direction would actually require. Proving P = NP would most likely mean exhibiting an explicit polynomial-time algorithm for some NP-complete problem, a "constructive" proof, though in principle a non-constructive proof of existence, without handing you the actual algorithm, is theoretically conceivable too. Proving P does not equal NP is believed by most researchers to require fundamentally new mathematical techniques for reasoning about the limits of computation, since every approach tried over the past five decades, including several major, well-publicised attempted proofs, has eventually been found to have a gap or a flaw. This is itself informative: the problem has resisted some of the most capable minds in the field for this long using every technique currently known, which is part of why it's regarded as one of the deepest open questions in all of mathematics and computer science, not merely a hard puzzle waiting for the right afternoon.
What to actually do about it as a working developer
You will almost never need to prove a problem is NP-complete from scratch at work. What's genuinely useful is pattern recognition: certain problem shapes (choosing an optimal subset under constraints, finding an optimal ordering or assignment, satisfying a web of interacting constraints) are the recurring fingerprints of NP-complete problems, and recognising the shape early saves you from chasing an exact, fast, general solution that almost certainly doesn't exist.
Once you suspect a problem is NP-complete, your practical options are usually one of these, and picking the right one is the actual skill:
- Shrink the input. If n is small and bounded (the brute-force timings measured earlier in this article show roughly n <= 20-25 staying under a few seconds for subset sum), exhaustive search is genuinely fine, and often simpler and more maintainable than a cleverer approach.
- Use a pseudo-polynomial algorithm, if one exists for your specific problem. Subset sum and the knapsack problem both have dynamic-programming solutions that are efficient when some other parameter (the target sum, the weight capacity) is small, even though they remain exponential in the number of bits in the worst case.
- Accept an approximation. Many NP-complete optimisation problems have known approximation algorithms with provable bounds (within some guaranteed percentage of optimal), which is often good enough in practice, and is how real-world routing, scheduling, and packing software mostly works.
- Use a heuristic or a modern solver. General-purpose SAT solvers and constraint solvers have gotten remarkably good at solving large real-world instances of NP-complete problems quickly, even though no polynomial-time guarantee exists for the worst case, because real-world instances rarely hit true worst-case structure.
The meta-skill underneath all four of these options is the same: once you suspect NP-completeness, stop treating "find the one correct general algorithm" as the only acceptable goal. Interviewers who ask NP-complete-adjacent questions, and real engineering managers who assign NP-complete-adjacent tickets, are very often testing exactly this judgment call, whether you'll burn a sprint chasing an exact algorithm that decades of research suggest doesn't exist, or whether you'll correctly identify the shape of the problem early and reach for one of the four practical paths above instead.
Common misconceptions worth clearing up
"NP means 'not polynomial'." No, this is probably the single most common mix-up. NP stands for "nondeterministic polynomial time", and it does not mean a problem is hard, it means a proposed solution can be verified in polynomial time. Every problem in P is also in NP, and plenty of easy problems are formally classified as being in NP.
"NP-hard and NP-complete are the same thing." They're related but distinct. NP-complete means a problem is in NP and is at least as hard as every other NP problem. NP-hard means a problem is at least as hard as every NP problem, but it doesn't require the problem itself to be in NP, some NP-hard problems are actually harder than anything in NP, and don't even have the "easy to verify" property.
"If a problem is NP-complete, there's no point even trying to solve it." This isn't right either. NP-completeness is a statement about the worst case over all possible inputs, and it says nothing about typical inputs, approximate answers, or small inputs. Real SAT solvers routinely solve NP-complete instances with millions of variables in practice, because real-world instances usually have exploitable structure that worst-case analysis doesn't account for.
"P vs NP being unsolved means we don't know anything useful about hard problems." We actually know an enormous amount: which problems are equivalent to each other (via reductions), which approximation guarantees are achievable, which special cases become tractable. The open question is narrow and specific, whether a general efficient algorithm exists for the whole class, not whether we understand these problems at all.
"This only matters for algorithms interviews." It shows up more often in ordinary system design than the academic framing suggests: any feature that quietly asks for "the best combination of X given constraints Y and Z" is worth a brief mental check against this list before committing to building an exact solver for it.
Frequently Asked Questions
What does NP actually stand for?
Nondeterministic polynomial time. In practice, the far more useful definition to actually remember is: a problem is in NP if a proposed solution to it can be checked for correctness in polynomial time, regardless of how hard that solution was to find in the first place.
Is P vs NP actually unsolved, or has someone secretly proven it?
It is genuinely unsolved as of today. It's one of the Clay Mathematics Institute's seven Millennium Prize Problems (named in 2000), each worth $1,000,000 for a correct proof, and it remains open. Occasional claimed proofs circulate online, but none has withstood peer review.
If P vs NP is unsolved, how do we know subset sum is NP-complete?
NP-completeness doesn't require resolving P vs NP. It only requires showing a problem is in NP, and that every other NP problem can be transformed into it via a polynomial-time reduction, both of which have been formally proven for subset sum, independent of whether P eventually turns out to equal NP or not.
Does this affect anything I'll actually build as a developer?
Yes, in a practical way: recognising that a problem you're facing (optimal scheduling, exact subset selection, certain routing problems) is NP-complete tells you to stop looking for a fast, exact, general algorithm and instead reach for approximation, heuristics, or constraining the input size, which this article measured directly for subset sum.
What's the difference between NP-hard and NP-complete?
NP-complete problems are in NP and are at least as hard as every other NP problem. NP-hard problems are at least as hard as every NP problem too, but aren't required to be in NP themselves, meaning some NP-hard problems don't even have the fast-to-verify property that defines NP in the first place.
