Today, we are back with another Python programming challenge. This time, we’ll work on the Count-and-Say problem from Leetcode. This challenge requires us to write a function that gives the nth term of the count-and-say sequence in Python.
What is the Count-and-Say Sequence
The count-and-say sequence, also known as the look-and-say sequence, is a sequence of integers that starts with 1.
Each subsequent integer in the sequence is generated by counting and reading off the digits in the previous integer, counting the number of digits in groups of the same digit.
Confused? The easiest way to understand count-and-say is to illustrate the steps using a string of letters.
Suppose I have the string
'aaabbaccd'
If I count-and-say the letters in the string, I’ll read the string as
Three 'a's, two 'b's, one 'a', two 'c's, one 'd'
since there are three ‘a’s in the string, followed by two ‘b’s, one ‘a’ and so on.
Now, if instead of a string of letters, suppose I have a string of digits, such as the string
'1125558'
I’ll read the string as
Two '1's, one '2', three '5's, one '8'
since there are two ‘1’s, one ‘2’, three ‘5’s and one ‘8’ in the string.
This is the main idea behind the count-and-say sequence.
One difference between the count-and-say sequence and what we did above is the count-and-say sequence expresses the frequency of each digit using numbers (instead of text such as ‘one’, ‘two’ and ‘three’).
Hence, the string above will be expressed as
21123518
Based on the concept covered above, we can generate the count-and-say sequence.
As mentioned previously, this sequence starts with the integer 1. To generate the other numbers in the sequence, we count-and-say the digits in the previous integer.
The first six terms of the sequence are given below:
1
11 (because the previous integer has one 1)
21 (because the previous integer has two 1s)
1211 (because the previous integer has one 2, followed by one 1)
111221 (because the previous integer has one 1, one 2 and two 1s)
312211 (because the previous integer has three 1s, two 2s and one 1)
Our job today is to write a function called countAndSay()
that accepts one argument – n
.
The function returns the nth term of the count-and-say sequence as a string. For instance, if n
equals 5, the function gives the 5th term in the sequence, which equals '111221'
.
Suggested Approach
To solve this problem, let’s consider the case where n
equals 5.
To get the 5th term for the count-and-say sequence, we need the 4th term, which equals '1211'
.
Let’s store this string in a variable called prevString
.
We’ll iterate through prevString
one character at a time to do the counting.
Say we store the result of the counting-and-saying in a variable called res
and use a variable called count
to keep track of the number of times a digit appears. At the beginning, res = ''
and count = 1
.
There are two cases where we need to update res:
Case 1 – When we find a new digit in prevString
Case 2 – After we finish iterating through the entire string.
Here’s how it works.
We’ll start with the second digit in prevString
('1211'
) and check if this digit is the same as the previous digit.
In this case, '2'
is not the same as '1'
. Hence, we need to update res
(Case 1). Specifically, we need to update res
to '11'
, since there is one ‘1’ previously.
Next, we move on to the third digit. This digit ('1'
) is again not the same as the previous digit ('2'
). Hence, we need to update res
(Case 1) again.
This time, we append the string '12'
(since there is one ‘2’ previously) to res
.
res
becomes '1112'
.
Next, we move on to the fourth digit. This digit ('1'
) is the same as the previous digit ('1'
). Hence, we do not need to update res
. However, we need to update count
to 2.
Finally, after iterating through all the digits in prevString
, we need update res
one last time (Case 2) by appending '21'
to res
.
res
becomes '111221'
, which is the required answer.
Based on the approach described above, try solving today’s challenge yourself.
Note that the approach described above starts with the 4th term ('1211'
) in the count-and-say sequence. In your solution, you need to figure out how to start with the 1st term ('1'
) in the sequence and use that to generate subsequent terms until you get the nth term.
Suggested Solution
Here’s the suggested solution for the count-and-say sequence problem in Python:
def countAndSay(n): if n == 1: return '1' prevString = '1' for i in range(1, n): res = '' count = 1 for j in range(1, len(prevString)): if prevString[j] == prevString[j-1]: count += 1 else: res = res + str(count) + str(prevString[j-1]) count = 1 res = res + str(count) + str(prevString[-1]) prevString = res return prevString
Here, we first define the countAndSay()
function on line 1.
Inside the function, we check if n
equals 1. If it does, we simply return '1'
as the result.
On the other hand, if n
is not '1'
, we need to generate all the relevant integers in the sequence. To do that, we’ll start with the first term '1'
. We assign this term to the prevString
variable on line 6.
Next, we use a for
loop to calculate the integers for the remaining (n – 1) terms in the sequence. The line
for i in range(1, n):
results in a for
loop that runs from i
equals 1 to i
equals (n-1). In other words, the loop runs (n-1) times, which is what we need.
Inside the for
loop, we first initialise res
to an empty string (line 9) and count
to 1 (line 10).
Next, we use an inner for
loop (lines 12 to 17) to do the actual counting.
When i
equals 1, prevString = '1'
, res = ''
and count = 1
.
The inner for
loop is not executed as range(1, len(prevString))
equals range(1, 1)
, which is empty. Hence, we move on to line 19, which updates res
to '11'
.
Next, we have line 20 which updates prevString
to '11'
.
After line 20, we move on to the next iteration for i
(i.e. we move back to line 9).
i
equals 2, res = ''
, count = 1
and prevString = '11'
now.
The inner for
loop is executed now as for j in range(1, len(prevString))
gives us for j in range(1, 2)
, which results in a for
loop that is executed once.
This inner for
loop performs the task described in the “Suggested Approach” section above.
Inside the for
loop, the if
condition evaluates to True
as prevString[1]
equals prevString[0]
. Hence, count
is incremented to 2.
Next, we move on to line 19 (as the inner for
loop is only executed once) and update res
and prevString
to '1121'
.
Next, we return to line 9 and repeat the whole process again. We keep doing that until the outer for
loop (lines 8 to 20) completes.
When that happens, we return the value of prevString
(on line 22).
On line 24, we call the countAndSay()
function using 5 as the argument.
If you run the code above, you’ll get
111221
as the output.