Chapter Nine · Designing Algorithms
Designing Algorithms
Chapters 7 and 8 met a handful of techniques inside particular algorithms; this chapter names them and prices each one as a way of thinking. Five topics: splitting a problem, committing to the best local step, answering each repeated subproblem once, trying and undoing, and algorithms that flip coins or are allowed a bounded error.
Merge sort, Dijkstra's algorithm and a spell-checker look like three unrelated pieces of code. They are three answers to one question: how should the work of solving a problem be organized? Merge sort splits the problem in half and trusts the halves. Dijkstra commits to the closest node and never looks back. The spell-checker notices that it keeps asking the same small questions and writes the answers down. Each choice of organization has a cost that can be read off before any code runs.
This chapter reads those costs. Divide and conquer is priced from a picture of its recursion. Greedy algorithms are fast, and correct only when a short swap argument says so. Dynamic programming trades a table of memory for exponential time, and it is how Lantern, the library search service, forgives a typo within two edits. Backtracking searches spaces too large to list by refusing to enter most of them. The last topic accepts a small, known error in exchange for enormous savings, with Lantern's Bloom filter as the example.
The problems that none of these techniques can tame, where the best known method is still exponential, are named here and left for Chapter 14.