Give an example where spending extra memory makes an algorithm dramatically faster, and explain what you are paying for.
Precomputing an index is the classic example. If you need to look up the positions of many words, scanning the list once to build a lookup table turns each later query into a constant-time operation. The space you spend is one entry per distinct key, and the time you save is a full scan per query.
words = ["alpha", "beta", "gamma", "alpha", "delta", "beta"]
index = {}
for position, word in enumerate(words):
index.setdefault(word, []).append(position)
print(index["alpha"], index["beta"])
print(len(words), len(index))The output shows the shape of the trade-off: the two keys that appeared twice have two positions each, and the six words collapsed into three distinct keys. Building the index cost one linear pass. After that, asking for the positions of alpha is a dictionary lookup, roughly constant time, instead of a scan of the whole list.
The cost is honest and worth naming. The index occupies memory proportional to the number of distinct keys, so a million distinct words means a million entries with their list overhead. It also has to be kept in step with the underlying list: if words are inserted or deleted, every stored position after that point shifts, and the index becomes wrong. That maintenance cost is what stops people from indexing everything.
The general rule: extra space is worth buying when it is proportional to the data you must query repeatedly, when the queries outnumber the updates, and when the resulting speedup is asymptotic rather than a constant. Build the index once, reuse it many times, and keep it small enough to fit the memory budget.