Reading the constraints backwards
The largest input a problem allows is a message about which technique is expected. Learn to read it before you write anything.
Every problem worth solving comes with limits: the list has at most this many entries, the values go up to that. Those numbers look like a detail about testing. They are usually the strongest hint available about what kind of solution is wanted, and reading them first saves writing the wrong thing.
The reasoning runs backwards from a budget. A current machine executes very roughly to simple operations per second, so a program with a one second budget can afford about operations. Work out what each growth class evaluates to at the given size, and cross off everything above the budget.
Change BUDGET to 10 ** 9 and run it again. Only one of the twelve verdicts changes.
At , a quadratic solution needs operations, which is around a hundred seconds. An solution needs about , which is instant. There is no tuning that closes that gap, and knowing it before you start is the difference between an hour of profiling and a different algorithm.
The table to keep in your head
| Largest n allowed | Intended cost | What that usually means |
|---|---|---|
| n up to about 11 | Theta(n!) | Try every ordering of the items |
| n up to about 22 | Theta(2^n) or Theta(2^n * n) | Try every subset of the items |
| n up to about 100 | Theta(n^4) | Four nested loops, or a table indexed by two pairs |
| n up to about 500 | Theta(n^3) | Three nested loops, or a table filled in over pairs |
| n up to about 5000 | Theta(n^2) | Every pair, or a table with one row per item |
| n up to about 10^6 | Theta(n log n) | Sorting, or a pass with a logarithmic operation inside |
| n up to about 10^7 | Theta(n) | A constant number of passes over the input |
| n up to 10^12 and beyond | Theta(log n) or Theta(1) | Arithmetic on the number itself, never a loop over it |
The rows are not laws. They are what the person who set the limit was thinking. If the stated limit is , they have deliberately excluded , which would be , and left room for , which is about . If they had wanted a quadratic solution they would have written .
The other numbers in the constraints
The size of the input is not the only limit worth reading. Several others change what is possible.
- The range of the values. If the entries are at most , an array with one slot per possible value is affordable and turns many searches into a direct lookup. If they are at most , it is not.
- The memory limit. A table of by numbers at is entries. At 8 bytes each that is 80 gigabytes, so the algorithm is impossible for reasons that have nothing to do with time.
- How many test cases there are. A limit of with up to separate cases is not a promise of ; look for a stated bound on the total, and if the total is what is bounded, budget against that.
- Whether the values can be negative, zero, or repeated. These rarely change the growth and very often change whether your procedure is correct.
Here is a worked reading. A problem says: up to items, each with a weight up to , and you must report something about every pair. The pair count alone is about , so the answer cannot be produced by examining pairs one at a time. The weights being up to rules out an array indexed by weight, and also warns that a sum of weights can reach , which overflows a 32-bit integer and needs a 64-bit one. Both conclusions came from the constraints, before any algorithm existed.
A problem allows n up to 18 and asks for the best possible arrangement of n items. What should you try first, and why is n = 18 the giveaway?
Something that looks at every subset, costing about 2 to the 18, which is 262144, or 2 to the n times n, about 4.7 million. Both are comfortable. The giveaway is that 18 is far too small for any polynomial cost to be the reason for the limit: if a quadratic solution existed, the setter would have allowed n in the thousands. A limit near 20 is the standard signal that exponential work over subsets is expected. If it had said n up to 11, the signal would be every ordering instead, since 11 factorial is about 40 million and 12 factorial is about 479 million.