Problem overview
The method countBinaryStrings receives an Int n and returns how many binary strings of length n do not contain two 1 characters in a row. For n = 3 the answer is 5: 000, 001, 010, 100 and 101. The other three strings of length 3, 011, 110 and 111, each contain 11. The statement guarantees n is at most 30.
There are 2^n binary strings of length n, and checking each of them would take far too long for n = 30. The lesson counts them with a recurrence instead.
Approach: look at how a valid string ends
Take a valid string of length i. Its last character is either 0 or 1:
- If it ends in
0, the firsti - 1characters can be any valid string of lengthi - 1. A trailing0never creates a pair of ones. - If it ends in
1, the character before it must be0, otherwise the string ends in11. So it ends in01, and the firsti - 2characters can be any valid string of lengthi - 2.
Those two cases cover every valid string exactly once, so
count(i) = count(i - 1) + count(i - 2)
This is the Fibonacci recurrence. It needs two starting values. There is one valid string of length 0, the empty string, and two of length 1, 0 and 1, since neither can hold two ones. Then count(2) is 3 (00, 01, 10), count(3) is 5, count(4) is 8, and so on.
Each value depends on the two before it, so the table is filled from the smallest length upward, which makes sure both values are ready when they are needed.
Step by step
- Create the table.
dpis a newArray[Int]of sizen + 1, declared withval. Entryiwill hold the count for lengthi. A new array starts filled with zeros. - Store the base cases.
dp(0) = 1anddp(1) = 2. Neither string of length 1 can contain two ones. - Loop over the longer lengths.
for (i <- 2 to n)runs from 2 toninclusive. - Apply the recurrence.
dp(i) = dp(i - 1) + dp(i - 2): strings ending in0plus strings ending in01. - Return
dp(n), the last entry of the table.
The solution in Scala
class Solution {
def countBinaryStrings(n: Int): Int = {
val dp = new Array[Int](n + 1)
dp(0) = 1
dp(1) = 2
for (i <- 2 to n) {
dp(i) = dp(i - 1) + dp(i - 2)
}
return dp(n)
}
}
The Scala details worth a closer look:
- Arrays are fixed-size and zero-filled.
new Array[Int](n + 1)reservesn + 1slots, all 0. The size can't change afterwards, so it has to include indexn. valfixes the name, not the elements.dpis aval, butdp(i) = ...still changes an element of the array.- Round brackets index arrays. Scala writes
dp(i - 1), notdp[i - 1]. Square brackets are for type parameters, as inArray[Int]. toanduntil.2 to nincludesn, while2 until nstops one short. Forn = 1the range2 to 1is empty, so the loop doesn't run and the method returnsdp(1).Intoverflow. The counts grow like Fibonacci numbers. Forn = 30the result is 2,178,309, which is small. AnIntholds values up to about 2.1 billion, and the table would stay correct up ton = 44. Forn = 45the sum wraps around silently and the method returns a negative number, -1323752223. The limit of 30 in the statement keeps the answers well in range.
Complexity
Time: O(n). The loop runs n - 1 times and does one addition each time.
Space: O(n). The table has n + 1 entries. Each entry needs only the previous two, so two running variables would use O(1) space.
Edge cases and common mistakes
n = 1. The answer is 2, from the base case. The loop doesn't run.n = 0. The statement allows a non-negativen, and the correct count is 1 for the empty string. This solution setsdp(1)on an array that has only index 0, so forn = 0it throws anArrayIndexOutOfBoundsException. Guarding the second base case withif (n >= 1)would fix it.- Using the wrong base case. Setting
dp(0) = 0shifts every result. Withdp(0) = 1anddp(1) = 2, the third entry is 3, as the strings00,01and10show. - Adding
dp(i - 1)twice. Treating a trailing1like a trailing0counts strings that end in11. A trailing1needs a0before it. - Allowing
11in the prefix. The prefix before a trailing01has lengthi - 2and is itself valid, which is why the term isdp(i - 2). - Table too small. Creating
dpwith sizenleaves no room fordp(n).
Testing
n = 1gives2.n = 2gives3.n = 3gives5.n = 4gives8.n = 10gives144.n = 30gives2178309.
