Patterns
Pattern clue sheet
Every clue from every lesson. Read a problem, find the words that match, and see which pattern they point to. One clue is a hint; two that agree are an answer.
What you are given
- Values in no useful order, and all you ask is whether one is there
- Hash set membership. A set does not need order. It finds a value by the value itself, and yes or no is all it answers.
- A rule gives the exact partner of each item
- Hash map lookup. When you know exactly which value you need, you do not search for it. You look it up as a key.
- Only lowercase letters, so at most 26 different values
- Frequency counting. The table of counts stays small however long the input is. A list of 26 numbers can be the whole table.
- The strings may contain any character at all
- Length-prefixed encoding. Any mark you put between strings can also appear inside one. A length cannot be confused with the contents.
- An empty string, and an empty list, must also come back exactly
- Length-prefixed encoding. A length of 0 is written like any other length. So an empty string is still written as something, and an empty list as nothing.
- Things open and close, one inside another
- Last-in, first-out stack. What opened last must close first. Keep the open ones on a stack, and each close only looks at the top.
- A linked list, and you may relink its nodes
- Linked list pointer rewiring. A node is reached only by following links. Putting nodes in a new order means changing those links, not shifting values as in an array.
- A list of operations to carry out, each with its arguments
- Purpose-built data structure. There is no single input to scan. You decide what to store so that each operation finds what it needs.
- A list sorted from smallest to largest, and a pair to find
- Opposing two pointers. In sorted order the two ends are the smallest and the largest. Their sum tells you which one is too small or too large to keep.
- A text and a shorter word; every candidate is as long as the word
- Fixed-size sliding window. The word fixes the window's length, even though no number k is given. Slide a window of that length along the text.
- A substring or subarray, and its length is not given
- Variable sliding window. Neighbors in order are what lies between two edges, and a rule must set the length. A subsequence, which may skip items, is not a window.
- The palindrome is a substring: its characters sit next to each other
- Expand around a center. With no gaps allowed, the two ends move away from one middle together. If characters may be skipped, there is no single middle to grow from.
- A list sorted from smallest to largest, and one value to find
- Binary search on a sorted range. Order lets one comparison rule out a whole side. Without order, every value has to be looked at.
- A sorted list was rotated: its first values moved to the end
- Binary search on a sorted range. It is still two sorted pieces. Comparing the middle with an end value tells which piece it is in, so half still goes.
- A budget to keep: finish within a given number of hours or days
- Binary search on the answer. The budget turns a guess into a yes or no question: does this guess stay within it? That question is the test.
- A path may join any two nodes, not only go down from the top
- Postorder tree recursion. Such a path climbs to one highest node and goes down again. That node needs the best way down on each side, and its children hand those up.
- The path to a node: the nodes from the root down to it
- Preorder tree recursion. The root is the top node. A problem that defines this path usually has a rule about it, and each parent hands down a summary of the path so far.
- The root is on level 0, its children on level 1
- Level-order tree traversal. A problem that numbers the levels usually wants an answer for each level, which is what this walk produces.
- The input is a binary search tree
- Binary search tree ordering. Its ordering lets one comparison rule out a whole side of a node, so most of the tree is never visited.
- Many words to look for at once, while letters come one at a time
- Trie. Words that begin the same share one path. One walk down the tree follows every word that still fits the letters so far.
- Values arrive one at a time, and the best k are wanted after each
- Heap of the best k. Updating a heap of k takes about log k steps. Sorting everything again after each new value is far slower.
- New items arrive, or change, between one take and the next
- Heap as a priority queue. A sorted list would have to be sorted again after each change. A heap puts one new item in its place in about log n steps.
- A growing collection of numbers, and the middle is asked for many times
- Two heaps. Sorting again for each question is too slow. Two heaps keep the middle on top while numbers are added.
- A path may not use the same cell twice
- Backtracking. A cell is marked while the path stands on it. The mark is removed on the way back, so that another path may use the cell.
- A grid whose cells are of two kinds, such as land and water
- Grid connected components. Cells of one kind that touch form regions. A problem that draws its grid this way usually asks something about those regions.
- Cells are joined side by side, and not at a corner
- Grid connected components. This sentence defines a region. It also names the neighbors to look at from each cell: up, down, left and right.
- Something spreads to every neighbor once per minute or per day
- Breadth-first search by distance. After t rounds it has reached everything t steps from where it began. The time a place is reached is its distance.
- One move changes a single letter, digit or position
- Breadth-first search by distance. Each value is a place and each allowed change is a step to a neighbor. No list of links is given: you make the neighbors when you need them.
- Each item has a list of the items it is joined to
- Graph traversal with a visited set. That is a graph. From any item you can step to its neighbors, then to theirs, and so reach everything connected to it.
- The links may lead round in a circle
- Graph traversal with a visited set. A walk with no memory would go round for ever. The visited set ends it: a node already in the set is not entered again.
- Each pair says one item must come before another
- Topological ordering. These are one-way requirements. Count for each item how many others must come first, and take the items whose count is 0.
- Links are added one at a time and never removed
- Union-find. Groups only merge and never split. One changed pointer merges two groups, so the structure is right after every new link.
- Each road has its own length, time or price
- Weighted shortest path. Counting links is wrong when costs differ: three cheap links can beat one costly link. The costs must be added along each route.
- A list of possible links, each with a cost
- Minimum spanning tree. You decide which links to build. Grow one tree, and always add the cheapest link that reaches a point outside it.
- Taking one item changes which later items you may take
- One-dimensional dynamic programming. No choice is safe on the spot, so both sides of every choice are compared. The cells keep that from repeating work.
- Each item has a size, and the total may not pass a limit
- Knapsack dynamic programming. Many different choices use the same amount, and only the best of them matters. So one cell for each amount is enough.
- Two strings to compare, match or turn into each other
- Two-dimensional dynamic programming. A smaller task is a start of one string with a start of the other. Every pair of lengths gets one cell of the table.
- A grid where each move goes only right or down
- Two-dimensional dynamic programming. A cell can be entered only from above or from the left. Its answer comes from those two cells, which are filled first.
- Only neighbors in the row can be joined or combined
- Interval dynamic programming. Whatever is joined last is made from a left part and a right part, and each part is a shorter stretch of the same row.
- Each operation changes which items are next to each other
- Interval dynamic programming. Then the first operation is hard to reason about. Ask which operation of a stretch comes last: its two sides never meet, so they are solved apart.
- A running total that must never drop below zero
- Greedy choice. The moment it drops below zero, everything before that point is ruled out together. One pass settles each point as it is met.
- A list of intervals, each a start and an end, in no order
- Sorted interval sweep. Sorted by start, the intervals that can touch each other become neighbors, so one walk compares each with what came before it.
- A number given as a list of digits, or one digit to a node
- Digit-by-digit arithmetic. The number is already cut into places. Do the arithmetic one place at a time, and pass a carry on to the next place.
- Every item has some of at most 30 yes or no properties
- Bit manipulation. One bit holds one yes or no, so a whole set fits in one number. AND and OR then combine two sets in one step.
What you are asked for
- Has this value been seen before?
- Hash set membership. The set holds everything met so far, so the question is one lookup for each value.
- Which values are in one list but not in the other?
- Hash set membership. Put one list in a set, then test each value of the other list against it.
- Return the positions of the two items that match
- Hash map lookup. A position must be remembered beside each item. A map from item to position gives it back in one step.
- Put the items that share a label into one group
- Hash map lookup. The label is the key, and the list of its items is kept beside it. Each item finds its group in one step.
- Which values appear most often, or at least k times?
- Frequency counting. How often is a question about counts. Count every value first, then choose from the counts.
- Do two lists hold the same items, in any order?
- Frequency counting. When order does not matter, two lists hold the same items exactly when every value has the same count in both.
- Compare what is left of a position with what is right of it
- Prefix and suffix passes. Each side is a running result. One pass from the left and one from the right give both sides to every position.
- For each position, a result from all the items except that one
- Prefix and suffix passes. All except one is everything before it together with everything after it. Each side is carried along in its own pass.
- Turn a list of strings into one string and back
- Length-prefixed encoding. The reader must know where each string ends. A length written in front says so, with no searching.
- Undo, cancel or go back to the most recent step
- Last-in, first-out stack. The step to take away is the newest one still kept, and that is the top of a stack.
- An item combines with, or cancels, the one right before it
- Last-in, first-out stack. After a cancel, the item before that becomes the neighbor. A stack keeps that earlier item ready on top.
- For each item, the next later item that is larger
- Monotonic stack. Items wait on the stack. A larger arrival takes off every smaller one, and it is the answer for each of them.
- The nearest earlier item that is smaller than this one
- Monotonic stack. Take off the earlier items that are not smaller. The top that is left is the nearest smaller one.
- How far an item reaches before a lower one stops it
- Monotonic stack. The reach ends at the nearest lower item on each side. One ordered stack finds both ends for every item.
- Return the same nodes in a new order
- Linked list pointer rewiring. No new node is needed. Each node keeps its value, and only its link is pointed somewhere else.
- Join two lists into one, or cut one list into parts
- Linked list pointer rewiring. A join or a cut is one link changed: the end of one part points at the start of another, or at nothing.
- Find the middle of a linked list in one pass
- Fast and slow pointers. When the fast pointer has covered the whole list, the slow one, at half the speed, has covered half of it.
- Does following the links ever come back to an earlier node?
- Fast and slow pointers. In a loop the fast pointer cannot leave. It gains one node on the slow one each round until it lands on it.
- The node that is k places before the end
- Fast and slow pointers. Start one pointer k nodes ahead and move both together. When the leader reaches the end, the other is k behind.
- Design a structure that supports these operations
- Purpose-built data structure. The work is choosing the parts. For each operation, ask which simple structure would answer it in one step.
- The same data must be found in two different ways
- Purpose-built data structure. One structure is fast for one way of asking. Keep a second one for the other way, and update both together.
- Does the whole string read the same forward and backward?
- Opposing two pointers. The first item must match the last, the second must match the one before last. Two positions moving inward check exactly those pairs.
- Choose two positions; the score grows with the distance between them
- Opposing two pointers. Start with the widest pair. Every move gives up distance, so leave the end that cannot score higher with any other partner.
- The largest total of any k items in a row
- Fixed-size sliding window. The length is given, so only the place of the window changes. Each move adds one item to the total and subtracts one.
- The longest run of neighboring items in which a rule holds
- Variable sliding window. Take items in on the right while the rule holds. When it breaks, dropping items on the left repairs it, so you never start over.
- The shortest run of neighboring items that reaches a goal
- Variable sliding window. Grow on the right until the goal is reached, then drop items on the left while it still is. Each drop gives a shorter candidate.
- The smallest value of every k items in a row
- Monotonic queue. A total can be corrected when an item leaves the window. A smallest value cannot, so you keep the values that could be smallest next.
- After each new reading, the highest of the last k readings
- Monotonic queue. A new reading that is higher makes every older, lower reading useless: the new one stays in the window longer. Drop them, and the highest is at the front.
- The longest palindrome inside a string
- Expand around a center. Every palindrome has a middle. Growing outward from each middle finds the longest one around it, and the longest of those is the answer.
- How many substrings are palindromes?
- Expand around a center. Each step outward that still matches is one more palindrome. Count the steps over all middles and none is missed or counted twice.
- The position of a value, or where it would go
- Binary search on a sorted range. In sorted data the smaller values come first. Halving finds where they stop, and that is the place of the value.
- The smallest speed, size or limit that is still enough
- Binary search on the answer. Smallest that is enough means a line between no and yes. When larger values stay enough, halving the range finds that line.
- The earliest time at which something becomes possible
- Binary search on the answer. When what is possible stays possible later, the times are a run of no and then a run of yes. Halving finds the first yes.
- Return the height, the size or the total of a tree
- Postorder tree recursion. For a node, each of these is made from its own part and the same number from each child. So the children must answer first.
- A rule at every node about the height or total of its two sides
- Postorder tree recursion. Each side's number is ready only after that side has finished. So the children report first, and the node tests the rule on the way back up.
- Each node needs its level, counted from the root
- Preorder tree recursion. A node cannot see above itself. Its parent knows its own level and passes that number plus one to each child.
- Write the tree out, each node before its children
- Preorder tree recursion. The node is handled first and its two sides after it, each side in the same way. That order is preorder.
- Return the values level by level, from the top down
- Level-order tree traversal. The queue hands the nodes over in exactly that order: all of one level before any node of the next.
- The largest, the total or the average value of each level
- Level-order tree traversal. Each of these needs all the nodes of one level together. The size of the queue when a level starts says where that level ends.
- The fewest steps down from the root to reach something
- Level-order tree traversal. Levels are read in order of distance from the root, so the first match met is the nearest and the walk can stop.
- In a binary search tree, the smallest value not below a given number
- Binary search tree ordering. At each node the comparison says whether a better value can only be on the left or only on the right.
- Return a binary search tree's values in sorted order, or its kth smallest
- Binary search tree ordering. Reading a node's left side, then the node, then its right side meets the values from smallest to largest.
- Does any stored word start with these letters?
- Trie. Walk the letters down from the root. If every step is there, at least one stored word begins that way.
- Match words letter by letter, where some letters are unknown
- Trie. A known letter has one step down to take. An unknown letter tries every step, and a path that spells no word is dropped early.
- Return the k largest values, or the kth largest
- Heap of the best k. Only k values can matter. A min-heap, a heap with its smallest on top, keeps them: the top is the weakest of the k.
- The k closest, cheapest or smallest of many items
- Heap of the best k. Keep k items in a max-heap, a heap with its largest on top. The top is the worst of the k kept, so a better item pushes it out.
- Take the largest (or smallest) item that is left, again and again
- Heap as a priority queue. The top of the heap is always that item. After it leaves, the next one comes to the top in about log n steps.
- Report the median after each new number
- Two heaps. The median, the middle value in sorted order, is where the smaller half meets the larger half. Both tops stand at that border.
- Split the values into a lower half and an upper half
- Two heaps. A max-heap, largest on top, holds the lower half. A min-heap, smallest on top, holds the upper half. Moving one top across keeps the sizes the same, or one apart.
- Return every possible way, or all the ways that keep a rule
- Backtracking. Every way must be built, so each one is made choice by choice. Undoing a choice lets the next way reuse the part before it.
- Place the pieces so that no rule is broken
- Backtracking. A rule can be tested after each piece. A piece that breaks it is taken back at once, with everything that would have followed.
- How many separate regions are there, or how large is the largest?
- Grid connected components. Each region is walked once, from the first of its cells that the scan meets. Count the walks, or count the cells in each walk.
- Which regions touch the edge of the grid?
- Grid connected components. Start the walks from the cells on the edge. Everything they reach touches the edge, and every region left unmarked does not.
- The fewest steps, moves or changes to get from A to B
- Breadth-first search by distance. Places leave the queue in order of distance. The first time the target appears, no shorter way to it can exist.
- The distance from each cell to the nearest of several sources
- Breadth-first search by distance. Put all the sources in the queue first, at distance 0. They spread together, and each cell is first reached from its nearest source.
- Can every node be reached from the first one?
- Graph traversal with a visited set. Walk from the first node and mark what you meet. Then compare the number of marked nodes with the number of nodes.
- Make a copy of every node, with the same links
- Graph traversal with a visited set. Keep a map from each node to its copy. It is the visited record, and it also gives the copy that a link must point to.
- Return an order in which everything can be done
- Topological ordering. Taking an item only when nothing it needs is missing builds such an order, from the front to the back.
- Can all of it be done, true or false?
- Topological ordering. It can, unless some requirements form a loop. Items in a loop never reach a count of 0, so they are never taken.
- Are these two already connected?
- Union-find. Two items are connected exactly when find gives the same leader for both. No walk along the links is needed.
- How many separate groups are there after each new link?
- Union-find. Start the count at the number of items. Each union of two different leaders leaves one group fewer.
- The cheapest, shortest or fastest way from a start
- Weighted shortest path. The answer is the smallest sum of costs along a route from the start. Keep the best sum known for each place and lower it link by link.
- The cheapest route that uses at most k links
- Weighted shortest path. Let each round read only the costs from before it, kept in a copy. Then a round lets every route grow by one link, so run k rounds.
- Connect all the points at the lowest total cost
- Minimum spanning tree. The cheapest way to join everything has no closed loop, so it is a tree that reaches every point: n points, n - 1 links.
- Count the ways to reach the end, or say if there is any way
- One-dimensional dynamic programming. You are asked how many or whether, not which. The answer for a position comes from the answers for the positions one move before it.
- The largest or smallest total you can get along a row
- One-dimensional dynamic programming. The best total up to a position is built from the best totals a few positions earlier. Each is worked out once and read later.
- Can some of the numbers add up to exactly this total?
- Knapsack dynamic programming. Which numbers made a sum does not matter, only that it can be reached. Mark each reachable sum in its cell, number by number.
- The fewest items, or the number of ways, to make an exact amount
- Knapsack dynamic programming. Take one item off the amount and a smaller amount is left. Its cell is already filled, so the answer is read, not worked out again.
- The longest part two strings share, or the fewest edits between them
- Two-dimensional dynamic programming. Look at the last item of each. Whatever is done with them leaves the same question for shorter strings, already answered in the table.
- The best total over every order of doing the operations
- Interval dynamic programming. The orders are far too many to try one by one. Many orders share the same stretches, so each stretch is solved once and reused.
- The largest number of items you can take, each counting as one
- Greedy choice. When every item counts the same, a choice is judged only by what it blocks. Often one choice blocks the least, and taking it first is safe.
- Can the last position be reached, when shorter moves are always allowed?
- Greedy choice. Then reaching far also means reaching everything nearer. One number, the farthest point so far, stands for all the routes.
- The largest sum of a run of neighbors, with negative numbers allowed
- Greedy choice. A run whose sum has dropped below zero only hurts what follows. Drop it and start again at the next number: one carried sum is enough.
- Do any two of the bookings overlap?
- Sorted interval sweep. After sorting by start, an overlap always shows between neighbors: a booking starts before the latest end so far. No other pair needs a look.
- The largest number of visits going on at the same moment
- Sorted interval sweep. Sort every start and every end as moments in time. Walking them in order, a count goes up at a start and down at an end.
- Return the values of the grid in a stated order
- Matrix traversal. The order is known before you start. Loops over the row and column numbers produce it, so nothing is searched and nothing is marked.
- Flip, turn or shift the whole grid
- Matrix traversal. The new cell of a value depends only on its old row and column. One rule with those two numbers moves every value.
- The result may need one more digit than the input has
- Digit-by-digit arithmetic. That extra digit is the carry left over after the first digit. A carry means the arithmetic is done place by place.
- A question about the digits of a whole number, such as their sum
- Digit-by-digit arithmetic. The remainder after dividing by 10 is the last digit. Dividing by 10 and rounding down removes it. Repeat, and the number comes apart digit by digit.
- The task asks about the 0s and 1s a number is stored as
- Bit manipulation. Bit operators reach single bits directly. AND with 1 reads the last bit, and a shift right moves the next bit into its place.
What the limits say
- Up to 100,000 values, so checking every pair for a repeat is too slow
- Hash set membership. Every pair is about 5 billion comparisons. One set check for each value is 100,000.
- Up to 100,000 items, and each needs its exact partner among the earlier ones
- Hash map lookup. Searching back from every item is about 5 billion steps. One lookup by key for each item is 100,000.
- You may not use division
- Prefix and suffix passes. Dividing the product of all the items by one item would take that item out. Without division, the two sides have to be built separately.
- Up to 100,000 items, so adding up each side again is too slow
- Prefix and suffix passes. Building both sides again for every position is about 10 billion steps. Two passes are 200,000.
- The reader gets only the one string, nothing else
- Length-prefixed encoding. Everything needed to split the text must be inside the text. The lengths are written in the text, in front of the strings.
- Up to 100,000 items, so looking back for a larger one is too slow
- Monotonic stack. Looking back from every item can take about 5 billion steps. On the stack each item goes on once and comes off at most once.
- Reorder the list in place, with only a few variables
- Linked list pointer rewiring. Changing links in place needs a few variables that each remember one node, and nothing more.
- Walk a chain using only a constant amount of extra memory
- Fast and slow pointers. Two variables are all it takes. Remembering every node you passed would need memory for the whole chain.
- Every operation must take constant time
- Purpose-built data structure. Constant time means a few steps however much is stored. A search through everything is ruled out, so something extra must be kept ready.
- Trying every pair is too slow, and extra space must stay constant
- Opposing two pointers. A table of values seen would cost memory. Two positions are two numbers, however long the list is, and together they move at most n places.
- k can be large, so adding up each stretch again is too slow
- Fixed-size sliding window. Adding up every window again costs about n times k steps. Updating the total costs two steps for each move, whatever k is.
- Up to 100,000 items, so trying every stretch is too slow
- Variable sliding window. There are about 5 billion stretches. Two edges that only move forward make at most 200,000 moves between them.
- Aim for O(n) time; searching each window again is too slow
- Monotonic queue. Searching every window costs about n times k steps. In the queue each value joins once and leaves once, about 2n steps.
- Palindromes in a string of at most 1,000 characters
- Expand around a center. About 2,000 middles, each grown at most 500 steps, is at most a million comparisons. Testing every substring on its own can take about 83 million.
- Aim for
O(log n)time - Binary search on a sorted range. Only halving is that fast. A list of 1,000,000 values is down to one position after about 20 looks.
- The answer can be as large as 1,000,000,000
- Binary search on the answer. Trying every value is a billion tests. Halving needs about 30, so each test can afford a full pass over the input.
- Up to 100,000 nodes, so no height or total can be worked out twice
- Postorder tree recursion. On a tree that is one long chain, working out the height again at every node costs about 5 billion steps. Handing it up costs one visit per node.
- The tree is balanced and holds a million values
- Binary search tree ordering. Balanced means no side is much deeper than the other. A path from the top to the bottom is then about 20 nodes, so a search takes about 20 steps.
- Many stored words, and a question about a beginning must not read them all
- Trie. A walk takes one step for each letter of the question. How many words are stored does not change that.
- n is very large and k is small
- Heap of the best k. Sorting costs about n log n steps and keeps all n values. A heap of k costs about n log k steps and keeps only k.
- Up to 100,000 items, so scanning them all for each take is too slow
- Heap as a priority queue. Scanning for the largest before every take is about 5 billion comparisons in total. A heap needs about 17 steps for one take.
- Up to 100,000 numbers, and the middle is asked for after each
- Two heaps. Sorting before every question is far too slow. A push or a pop takes about 17 steps, and the middle is read in one.
- The input has at most about 20 items
- Backtracking. Trying every way grows very fast: 20 yes-or-no choices give 1,048,576 ways. A limit this small says that trying them all is expected.
- Thousands of items and pairs, so trying every order is far too slow
- Topological ordering. Ten items already have 3,628,800 possible orders. This method reads each item once and each pair twice.
- Up to 100,000 items, and 100,000 questions mixed in with the links
- Union-find. A new walk for every question can be about 10 billion steps in all. A find climbs only a few pointers.
- Up to 1,000 points, and any two of them may be linked
- Minimum spanning tree. That is about 500,000 possible links, far too many to try in sets. Growing the tree takes about 2 million steps.
- Up to 100 items, and each one is a yes or no choice
- One-dimensional dynamic programming. Trying every mix of choices is 2 to the power 100, far too many. One cell for each position is about 100 cells.
- The limit or the target total is at most a few thousand
- Knapsack dynamic programming. The row has one cell for each amount from 0 to the limit, so the limit must be small enough to walk through.
- Both strings have up to 1,000 letters
- Two-dimensional dynamic programming. That is about a million pairs of lengths, one cell each, which is fast. Trying every way to line the letters up is not.
- The row has at most a few hundred items
- Interval dynamic programming. Every stretch with every split is about 4.5 million steps for 300 items. A limit this small leaves room for such a table.
- Up to 100,000 intervals, so comparing every pair is too slow
- Sorted interval sweep. Every pair is about 5 billion comparisons. Sorting takes about 1.7 million steps, and the walk after it 100,000.
- Move the values inside the grid itself; a second grid is not allowed
- Matrix traversal. Values must trade places directly. The walk is planned so that every value moves once and none is written over before it has moved.
- You may not turn the whole string into a number
- Digit-by-digit arithmetic. The built-in arithmetic is ruled out, and in many languages a long number would not fit. The paper method needs only one digit and a carry.
- The + and - operators are not allowed
- Bit manipulation. When ordinary arithmetic is ruled out, only the bits are left to work with. The bit operators can rebuild it from them.
- Every value comes twice except one, and extra memory must stay constant
- Bit manipulation. XOR, written
^, gives 0 for two equal numbers. So pairs cancel each other, and one number does the work of a set.