Answers · Making it fast enough
Why is O(2n) treated the same as O(n)?
In shortBecause it describes how cost grows rather than exact cost, doubling every cost does not change the growth class.
Because big O describes the growth of cost, not the exact cost, and multiplying every cost by two does not change growth. Doubling every term moves the line up but leaves it a line. The rest is the definition doing exactly what it says.
The definition does it
Write the claim in full: means there are a constant and a size such that for every . The in is not sitting outside that inequality. It is one more number that can be folded into . To show is , take . Choose and . Then for every , , which is true by equality. The claim is satisfied, and nothing about the factor has been denied.
Put numbers in and the scale is plain. At , a cost of is operations and a cost of is . The ratio is . A quadratic cost at the same size is operations, which is times the linear one: . The factor is a difference of two; the shape is a difference of five hundred thousand. At the scale where growth classes are meant to be read, the second difference is the one that decides.
The natural guess is that records the and does not, so the first must be a larger class. That treats the expression inside as if it were the running time itself. It is not. is not twice ; the notation does not multiply that way. Both expressions name the same set of functions, the ones bounded by a straight line for large enough . If the were meant to survive, the question would be about the exact cost, or about which of two linear procedures is faster, and is deliberately blind to both.
The equality is not just one absorption; it is mutual. If , then some and give for . Set . Then , so . Conversely, if with constant , then , so . A factor of two can be moved from the function into the constant or from the constant into the function. That is why the two claims are the same claim.
The factor is not unreal
None of this says the factor is imaginary. It says the factor belongs to the implementation and the machine, and to the small inputs, rather than to the growth class. A procedure that does work is twice as slow as one that does work at the same , if the constant is the same. On a list of ten items that is the difference between twenty operations and ten. If the input never gets large, that difference is the whole story, and asking for the growth class is asking the wrong question. The convention is a statement about the limit, not a promise about today.
A larger constant can even reverse the early winner. Compare with . At , and , so the linear procedure is ten times more work. At , both are . At , and , so the quadratic procedure is one hundred times more work. The constant set the crossing point at and the shape controlled everything after it. Dropping constants is safe for the eventual comparison and unsafe for the early one.
Same shape, no answer
The other place the convention goes quiet is when two procedures have the same shape. If both are , the growth statement rates them identically and is correct to: neither collapses as the data grows. It cannot tell you which to ship today. The only instrument left is measurement, because the difference is now entirely in the constant, in cache behaviour, in the language, and in the inner loop. A factor of two hundred between two linear procedures is possible and the notation will not show it. That is not a failure of the notation; it is the boundary of what the notation was built to answer.
Worth keeping
- A constant factor moves the running time up or down but does not change how it grows with input size.
- The definition of big O hides a constant, so a factor of two can be absorbed by changing that constant.
- Constants decide small inputs and equal shapes; growth shapes decide large inputs.
Where this goes next
This question is one step of How Long It Takes, a course that works through its subject from the beginning. The page that teaches this part of it is Why the Constants Get Dropped, and it reads the whole way through whether or not you have an account.
What an account changes is the practice: problems standing under every idea, marked with a reason rather than a tick, in a copy of the course that is yours.
Read that pageThe whole courseOther questions people ask about this
- Which grows faster, n log n or n squared?The squared option grows faster: doubling the input multiplies the log-times-linear option by a little over two, but multiplies the squared option by four.
- Why do nested loops multiply their running times instead of adding them?Because the inner loop runs in full once for every pass of the outer loop, so the cost is one count times the other, not one plus the other.
- Why doesn't breadth-first search give the cheapest path once the links have different costs?Breadth-first search counts links rather than costs, so it can return a route with fewer links that is more expensive than a longer route.
- How does a hash function turn a word into an array index?A hash function reads the word as bytes, mixes them into one large number, then takes the remainder after dividing by the table size to get an index from zero to size minus one.
- How can you check whether something is in a set without storing every item?Record a few hashed marks per item in a bitmap; all marks set means probably present, any mark clear means certainly absent.
- What's the difference between memoized recursion and filling a DP table bottom-up?Memoised recursion keeps the calls and only solves states it reaches; a bottom-up table removes the calls, fills every entry in a dependency-safe order, and is usually faster when most entries are needed.