The Birthday Problem
Sequential access processes array elements one after another in array order, while random access lets you reach any element directly at any time.
Waiting for a Shared Birthday
Suppose you walk into a room and start asking people for their birthdays. How long do you expect to wait before someone shares a birthday with a person you already asked? Most people give an answer that is much larger than what actually happens. This gap between expectation and reality is the starting point for this article. It also shows one of the most useful properties of arrays, random access, and how a simple array lets a program answer the question quickly.
Keep one question in mind as you read: when a program wants the value at one particular position, how does it get there? The answer depends on whether the access is direct, and the rest of this article explains what that means and why it matters.
Two Ways to Visit an Array
Up to this point, the array examples in the course have used sequential access. In sequential access, the elements of an array are processed one after another, in the order they appear. You start at the first position, move to the second, then the third, and so on until you finish. Many useful tasks look like this, such as totaling all the values in a list or scanning for the largest one.
Sequential access describes how the work is ordered, not a limit on what the array can do. When a problem asks you to visit elements in order, sequential processing is the natural fit. The birthday problem does not fit that pattern, and that is where random access becomes important.
Random access means that every element of the array is equally accessible at any given time. Your program does not need to walk through the earlier positions to reach a later one. If you want the element at a particular position, you can go straight to it, whether that position is the first, the middle, or the last.
| Aspect | Sequential access | Random access |
|---|---|---|
| Order of visits | Position by position, in array order | Any position, in any order |
| How a position is reached | Passing through the earlier positions first | Naming the position directly |
| Typical use | Totaling values, scanning for the largest | Looking up a slot the next step could need, anywhere in the array |
| Cost of reaching a later position | Must walk past the earlier ones | Same single direct step as any other position |
Sequential access versus random access to array elements
Why Every Slot Is Equally Reachable
An array holds a group of values, and each value sits at a numbered position. Positions label the slots, while the values are the contents stored in those slots. The word direct carries the main idea: an array element is identified by its position, so the program can jump straight to the position it needs. Whether that position is first, last, or in the middle makes no difference to how the program reaches it.
This is why arrays are used whenever a program must revisit a specific slot again and again. The source presents this as the defining ability of arrays. Because no slot is closer or more reachable than another, the cost of reaching index 4 is the same as the cost of reaching index 0.
The short Java program below is an original illustration, not the source file. It shows the core move: naming a position in brackets returns the value stored there. The program does not loop through the array to find the value.
false
true- new boolean[5] creates five slots with positions 0 to 4
- used[2] names position 2 directly, without touching used[0] or used[1]
- Assigning used[2] = true changes only that one slot
Changing the number inside the brackets changes which element is returned, and the program reaches any of them in the same single step. This is the behavior the birthday problem relies on when it looks up a day.
Tracing Index 3 Without Visiting Earlier Slots
The source uses a five-position diagram, which is a small stand-in for the 365-slot array the birthday problem needs. Each cell can be reached by its index. To check day number 2, the program names used[2] and reads it. It does not need to inspect used[0] or used[1] first. Those two cells hold true and false respectively, but they have no bearing on the lookup of position 2.
Looking up day 2 in a five-slot array
The program needs to know whether day 2 has been marked, using the five-slot illustration.
- 1Name the position
The program writes used[2], which identifies slot 2 by its index.
- 2Go straight there
The request goes to slot 2. The program does not pass through slot 0 or slot 1.
- 3Read the value
The value stored in that slot is returned. Its neighbors, which hold true and false, do not affect this lookup.
The program has the value at position 2 in a single step, regardless of where that position sits in the array.
What the Birthday Simulation Remembers
To simulate the birthday experiment, the program must remember which birthdays it has already seen. There are 365 possible birthdays, and the setup ignores leap years. For each possible birthday, the program needs one piece of information: has someone with this birthday already been found? The answer is a boolean value. Gathering 365 boolean answers into one structure is exactly what an array is for.
Each slot corresponds to one day number. The value in used[i] is true if someone whose birthday is day number i has already been selected, and false otherwise. The index does the work of identifying the day. The program never searches the array for a matching birthday. It jumps straight to the slot that matches the birthday it just drew.
New boolean arrays start with false in every slot, so unseen birthdays need no setup before they are checked. The same idea explains why the array is initialized with false values: every day is ready to be checked the moment the simulation begins.
What do you think happens?
The array is created fresh and no birthdays have been recorded yet. What does used[17] hold before the simulation picks anyone?
Reveal answer
false
A new boolean array starts with false in every slot, so the slot for day 17 holds false, meaning that birthday has not been seen.
Recording and Checking a Drawn Birthday
Each time the simulation picks a person, the birthday drawn could be any day from 0 to 364. The next birthday has no relationship to the previous one, so the program cannot know in advance which slot it will need. A purely sequential scan would waste effort walking past slots that have nothing to do with the new birthday. Random access solves this: the program computes the day number, reads used at that index, and either stops or records the day as used.
- 1Draw a random day number from 0 to 364.
- 2Name that day as the index and read used at that index in one direct step.
- 3If the value is true, someone with this birthday has already been selected, so the simulation stops.
- 4If the value is false, set used at that index to true to record that the day has now been seen.
- 5Draw the next person's birthday and repeat, with no scan of the other slots.
Mistakes About Reaching Array Elements
Common mistake Assuming you must start at the front of the array and step forward to reach a later element.
What it looks likeBelieving that to read used[3] the program has to check used[0], then used[1], then used[2].
Why it failsRandom access means every element is equally accessible at any time. The index names the position directly, so the earlier slots are not visited.
Do this insteadName the index you need, such as used[3], and read that slot in one step.
Common mistake Confusing the position label with the value stored there.
What it looks likeTreating the 2 in used[2] as the value held in that slot.
Why it failsPositions label the slots, while the values are the contents stored in those slots.
Do this insteadRead the 2 as the position. The value is whatever the slot holds, such as true or false.
Common mistake Assuming a new boolean array needs its slots set to false before the simulation can check them.
Practice Tracing a Lookup
A boolean array named used has five slots, positions 0 to 4, all false. The program draws day 3, reads used[3], finds false, and then sets used[3] to true. Next, it draws day 3 again. Trace which slots are read and which are changed during the second draw, and state whether the program had to visit used[0], used[1], or used[2] at any point.
Hints
- Reread how a drawn day is used as an index.
- Ask whether the second draw needs any slot other than the one named by its index.
- Check the step where a value of true means a shared birthday was found.
Key Takeaways
- Sequential access visits array elements one after another in array order, while random access reaches any element directly by its position.
- Every element of an array is equally accessible at any given time, so a program can go straight to the slot it needs without passing through earlier positions.
- The birthday problem uses a boolean array of 365 slots, where the index is the day number and the value records whether that birthday has been seen; new boolean arrays start with false in every slot.
- Because each drawn birthday can point to any slot, random access lets the simulation read and record a day in a single direct step.