Problem overview
The method countBinaryStrings receives an Int n and returns how many binary strings of length n exist. A binary string uses only the characters 0 and 1, and any combination is allowed. For n = 3 there are 8 of them: 000, 001, 010, 011, 100, 101, 110 and 111. The statement guarantees n is at most 30.
The lesson asks for the count, not for the strings themselves. Listing them would take time proportional to their number, which doubles with every extra character. Counting them can be done with a short loop.
Approach: extend every shorter string in two ways
Take any binary string of length i. Removing its last character leaves a binary string of length i - 1. In the other direction, each string of length i - 1 can be extended by appending 0 or by appending 1, and the two results are different strings. Every string of length i comes from exactly one string of length i - 1 and one choice of last character, so
count(i) = 2 * count(i - 1)
This is a small dynamic programming problem: the answer for length i is computed from the answer for the length before it. The base case is length 1, where the only strings are 0 and 1, so the count is 2. From there, 4, 8, 16 and so on follow. The closed form is 2 to the power n. The table is still worth writing, because the same pattern, a table filled in increasing order, solves harder counting problems, and this one makes the recurrence visible.
Step by step
- Create the table.
dpis anArray[Int]of sizen + 1, so that indexnexists. Entryiwill hold the number of binary strings of lengthi. A newArray[Int]starts with all zeros. - Set the base case.
dp(1) = 2, because a string of length 1 is either"0"or"1". - Loop over the longer lengths.
for (i <- 2 to n)visits2, 3, ..., n. The range2 to nincludesn, and every entry is computed after the one before it. - Apply the recurrence.
dp(i) = dp(i - 1) * 2: each shorter string can be extended by a0or by a1. - Return
dp(n), which holds the count for the full length.
The solution in Scala
class Solution {
def countBinaryStrings(n: Int): Int = {
val dp = new Array[Int](n + 1)
dp(1) = 2
for (i <- 2 to n) {
dp(i) = dp(i - 1) * 2
}
return dp(n)
}
}
The Scala details worth a closer look:
- Creating the array.
new Array[Int](n + 1)makes an array of that size with every element set to 0. Its size is fixed from then on. valfixes the name, not the elements.dpis aval, yetdp(i) = ...still works, because it changes an element of the array thatdprefers to.- Round brackets for elements. Scala reads and writes array elements with
dp(i), notdp[i]. The assignmentdp(1) = 2is shorthand for a call to the array'supdatemethod. toincludes its end,untilexcludes it.2 to nends atn. Ifnis 1, the range2 to 1is empty and the loop body never runs, which is correct, sincedp(1)is already set.Intis 32 bits. The largest value here, forn = 30, is 1,073,741,824, which fits. One more doubling would give 2,147,483,648, which is beyond the largestIntand wraps to -2,147,483,648 without any error. That is why the statement stops at 30. For larger lengths, aLongwould be needed.
Complexity
Time: O(n). The loop runs at most n - 1 times and each pass does one multiplication.
Space: O(n). The table has n + 1 entries. Only the previous entry is ever read, so a single running variable would reduce the space to O(1), and 1 << n gives the answer directly.
Edge cases and common mistakes
n = 1. The loop body is skipped and the method returnsdp(1), which is 2.n = 0. The statement allows a non-negativen, and the one string of length 0 is the empty string, so the count should be 1. This solution creates an array with a single entry and then writes todp(1), which doesn't exist, so it throws anArrayIndexOutOfBoundsException. Settingdp(0) = 1as the base case and starting the loop at 1 would cover it.- Array too small. Creating
dpwith sizeninstead ofn + 1makesdp(n)an invalid index. - Using
until.2 until nstops beforen, sodp(n)stays 0. - Wrong base case. Starting with
dp(1) = 1halves every result. - Using
^for powers. In Scala,^is bitwise exclusive or, not exponentiation, so2 ^ 3is 1. Use1 << normath.powfor powers of two.
Testing
n = 1gives2.n = 2gives4.n = 3gives8.n = 10gives1024.n = 30gives1073741824.
