Find the nth term in Look-and-say (Or Count and Say) Sequence. The look-and-say sequence is the sequence of the below integers: 1, 11, 21, 1211, 111221, 312211, 13112221, 1113213211, ...
How is the above sequence generated?
The nth term is generated by reading (n-1)th term.
- The first term is "1"
- Second term is "11", generated by reading first term as "One 1" (There is one 1 in previous term)
- Third term is "21", generated by reading second term as "Two 1"
- Fourth term is "1211", generated by reading third term as "One 2 One 1" and so on
Examples:
Input: n = 3
Output: 21
Explanation: The 3rd term of the sequence is 21
- 1st term: 1
- 2nd term: one 1 -> 11
- 3rd term: two 1s -> 21
Input: n = 4
Output: 1211
Explanation: The 4th term of the sequence is 1211
- 1st term: 1
- 2nd term: one 1 -> 11
- 3rd term: two 1s -> 21
- 4th term: one 2 one 1 -> 1211
Input: n = 1
Output: 1
Explanation: The first term of the sequence is 1
Using Recursive - O(2^n) Time and O(n + 2^n) Space
Idea is to recursively call for n-1 to generate the previous term. Then we build the nth or current term using the (n-1)th or previous term
How to build current term using previous? To generate a term using the previous term, we scan the previous term. While scanning a term, we simply keep track of the count of all consecutive characters. For a sequence of the same characters, we append the count followed by the character to generate the next term.
Step by Step Algorithm:
- Call the function recursively to get the
(n-1)
th term : prev = countAndSay(n - 1)
- Initialize res
= ""
and count = 1.
- Loop through the
prev
string from index 1: - If
prev[i] == prev[i - 1]
, increment count.
Else: append count
and prev[i - 1]
to result and r
eset count = 1
- After the loop, append the count of last character followed by the last character. Note that in the loop, we process previous character, so the last character has to be processed separately.
C++
#include <bits/stdc++.h>
using namespace std;
// Helper function to generate the next term
// in the sequence from the previous one
string nextTerm(string& prev) {
string curr = "";
int count = 1;
for (int i = 1; i < prev.length(); i++) {
// Keep Counting while same
if (prev[i] == prev[i - 1]) {
count++;
// If a different character found, appemd
// the count of previous character along
// with the character itself
} else {
curr += to_string(count) + prev[i - 1];
count = 1;
}
}
// Append the last character's count and the
// last character
curr += to_string(count) + prev.back();
return curr;
}
// Recursive function to return the nth term
string countAndSay(int n) {
// Base case
if (n == 1)
return "1";
// Recursively get the previous term
string prev = countAndSay(n - 1);
// Get the n-th term using (n-1)th
return nextTerm(prev);
}
// Driver code
int main() {
int n = 5;
cout << countAndSay(n) << endl;
return 0;
}
Java
// Helper function to generate the next term
// in the sequence from the previous one
class GfG {
public static String nextTerm(String prev) {
StringBuilder curr = new StringBuilder();
int count = 1;
for (int i = 1; i < prev.length(); i++) {
// Keep Counting while same
if (prev.charAt(i) == prev.charAt(i - 1)) {
count++;
// If a different character found, append
// the count of previous character along
// with the character itself
} else {
curr.append(count).append(prev.charAt(i - 1));
count = 1;
}
}
// Append the last character's count and the
// last character
curr.append(count).append(prev.charAt(prev.length() - 1));
return curr.toString();
}
// Recursive function to return the nth term
public static String countAndSay(int n) {
// Base case
if (n == 1)
return "1";
// Recursively get the previous term
String prev = countAndSay(n - 1);
// Get the n-th term using (n-1)th
return nextTerm(prev);
}
// Driver code
public static void main(String[] args) {
int n = 5;
System.out.println(countAndSay(n));
}
}
Python
# Helper function to generate the next term
# in the sequence from the previous one
def nextTerm(prev):
curr = ""
count = 1
for i in range(1, len(prev)):
# Keep Counting while same
if prev[i] == prev[i - 1]:
count += 1
# If a different character found, append
# the count of previous character along
# with the character itself
else:
curr += str(count) + prev[i - 1]
count = 1
# Append the last character's count and the
# last character
curr += str(count) + prev[-1]
return curr
# Recursive function to return the nth term
def countAndSay(n):
# Base case
if n == 1:
return "1"
# Recursively get the previous term
prev = countAndSay(n - 1)
# Get the n-th term using (n-1)th
return nextTerm(prev)
# Driver code
if __name__ == "__main__":
n = 5
print(countAndSay(n))
C#
using System;
using System.Text;
// Helper function to generate the next term
// in the sequence from the previous one
class GfG {
public static string nextTerm(string prev) {
StringBuilder curr = new StringBuilder();
int count = 1;
for (int i = 1; i < prev.Length; i++) {
// Keep Counting while same
if (prev[i] == prev[i - 1]) {
count++;
// If a different character found, append
// the count of previous character along
// with the character itself
} else {
curr.Append(count).Append(prev[i - 1]);
count = 1;
}
}
// Append the last character's count and the
// last character
curr.Append(count).Append(prev[prev.Length - 1]);
return curr.ToString();
}
// Recursive function to return the nth term
public static string countAndSay(int n) {
// Base case
if (n == 1)
return "1";
// Recursively get the previous term
string prev = countAndSay(n - 1);
// Get the n-th term using (n-1)th
return nextTerm(prev);
}
// Driver code
public static void Main(string[] args) {
int n = 5;
Console.WriteLine(countAndSay(n));
}
}
JavaScript
// Helper function to generate the next term
// in the sequence from the previous one
function nextTerm(prev) {
let curr = "";
let count = 1;
for (let i = 1; i < prev.length; i++) {
// Keep Counting while same
if (prev[i] === prev[i - 1]) {
count++;
} else {
// If a different character found, append
// the count of previous character along
// with the character itself
curr += count.toString() + prev[i - 1];
count = 1;
}
}
// Append the last character's count and the
// last character
curr += count.toString() + prev[prev.length - 1];
return curr;
}
// Recursive function to return the nth term
function countAndSay(n) {
// Base case
if (n === 1) {
return "1";
}
// Recursively get the previous term
const prev = countAndSay(n - 1);
// Get the n-th term using (n-1)th
return nextTerm(prev);
}
// Driver code
const n = 5;
console.log(countAndSay(n));
Why is the time complexity exponential?
The next term can be at-most double the size of previous term. We get double size when all characters are different. So an upper bound on the time complexity would be O(2n). We need this long string also for output and O(n) space for recursion. That is why the space is O(2n + n).
Iterative Solution - O(2^n) Time and O(2^n) Space
Instead of recursively generating the previous term, we build all terms one by one from first term which is "1" to the nth term. To generate the next term, we use the same idea as used in the above recursive solution.
C++
#include <bits/stdc++.h>
using namespace std;
// Iterative function to return the nth term
string countAndSay(int n) {
if (n == 1)
return "1";
string curr = "1";
// Start from the second term, build every term
// terms using the previous term
for (int i = 2; i <= n; i++) {
string next = "";
int cnt = 1;
for (int j = 1; j < curr.length(); j++) {
// If same as previous, then increment
// count
if (curr[j] == curr[j - 1]) {
cnt++;
// If different process the previous
// character and its count and reset
// count for the current character
} else {
next += to_string(cnt) + curr[j - 1];
cnt = 1;
}
}
next += to_string(cnt) + curr.back();
curr = next;
}
return curr;
}
// Driver code
int main() {
int n = 5;
cout << countAndSay(n) << endl;
return 0;
}
Java
// Iterative function to return the nth term
class GfG {
public static String countAndSay(int n) {
if (n == 1) return "1";
String curr = "1";
// Start from the second term, build every term
// terms using the previous term
for (int i = 2; i <= n; i++) {
StringBuilder next = new StringBuilder();
int cnt = 1;
for (int j = 1; j < curr.length(); j++) {
// If same as previous, then increment
// count
if (curr.charAt(j) == curr.charAt(j - 1)) {
cnt++;
// If different process the previous
// character and its count and reset
// count for the current character
} else {
next.append(cnt).append(curr.charAt(j - 1));
cnt = 1;
}
}
next.append(cnt).append(curr.charAt(curr.length() - 1));
curr = next.toString();
}
return curr;
}
// Driver code
public static void main(String[] args) {
int n = 5;
System.out.println(countAndSay(n));
}
}
Python
# Iterative function to return the nth term
def countAndSay(n):
if n == 1:
return "1"
curr = "1"
# Start from the second term, build every term
# terms using the previous term
for i in range(2, n + 1):
nextStr = ""
cnt = 1
for j in range(1, len(curr)):
# If same as previous, then increment
# count
if curr[j] == curr[j - 1]:
cnt += 1
# If different process the previous
# character and its count and reset
# count for the current character
else:
nextStr += str(cnt) + curr[j - 1]
cnt = 1
nextStr += str(cnt) + curr[-1]
curr = nextStr
return curr
# Driver code
if __name__ == "__main__":
n = 5
print(countAndSay(n))
C#
// Iterative function to return the nth term
using System;
class GfG{
public static string countAndSay(int n) {
if (n == 1) return "1";
string curr = "1";
// Start from the second term, build every term
// terms using the previous term
for (int i = 2; i <= n; i++) {
string next = "";
int cnt = 1;
for (int j = 1; j < curr.Length; j++) {
// If same as previous, then increment
// count
if (curr[j] == curr[j - 1]) {
cnt++;
// If different process the previous
// character and its count and reset
// count for the current character
} else {
next += cnt.ToString() + curr[j - 1];
cnt = 1;
}
}
next += cnt.ToString() + curr[curr.Length - 1];
curr = next;
}
return curr;
}
// Driver code
public static void Main() {
int n = 5;
Console.WriteLine(countAndSay(n));
}
}
JavaScript
// Iterative function to return the nth term
function countAndSay(n) {
if (n === 1) return "1";
let curr = "1";
// Start from the second term, build every term
// terms using the previous term
for (let i = 2; i <= n; i++) {
let next = "";
let cnt = 1;
for (let j = 1; j < curr.length; j++) {
// If same as previous, then increment
// count
if (curr[j] === curr[j - 1]) {
cnt++;
// If different process the previous
// character and its count and reset
// count for the current character
} else {
next += cnt.toString() + curr[j - 1];
cnt = 1;
}
}
next += cnt.toString() + curr[curr.length - 1];
curr = next;
}
return curr;
}
// Driver code
const n = 5;
console.log(countAndSay(n));
Similar Reads
DSA Tutorial - Learn Data Structures and Algorithms DSA (Data Structures and Algorithms) is the study of organizing data efficiently using data structures like arrays, stacks, and trees, paired with step-by-step procedures (or algorithms) to solve problems effectively. Data structures manage how data is stored and accessed, while algorithms focus on
7 min read
Quick Sort QuickSort is a sorting algorithm based on the Divide and Conquer that picks an element as a pivot and partitions the given array around the picked pivot by placing the pivot in its correct position in the sorted array. It works on the principle of divide and conquer, breaking down the problem into s
12 min read
Merge Sort - Data Structure and Algorithms Tutorials Merge sort is a popular sorting algorithm known for its efficiency and stability. It follows the divide-and-conquer approach. It works by recursively dividing the input array into two halves, recursively sorting the two halves and finally merging them back together to obtain the sorted array. Merge
14 min read
Data Structures Tutorial Data structures are the fundamental building blocks of computer programming. They define how data is organized, stored, and manipulated within a program. Understanding data structures is very important for developing efficient and effective algorithms. What is Data Structure?A data structure is a st
2 min read
Bubble Sort Algorithm Bubble Sort is the simplest sorting algorithm that works by repeatedly swapping the adjacent elements if they are in the wrong order. This algorithm is not suitable for large data sets as its average and worst-case time complexity are quite high.We sort the array using multiple passes. After the fir
8 min read
Breadth First Search or BFS for a Graph Given a undirected graph represented by an adjacency list adj, where each adj[i] represents the list of vertices connected to vertex i. Perform a Breadth First Search (BFS) traversal starting from vertex 0, visiting vertices from left to right according to the adjacency list, and return a list conta
15+ min read
Binary Search Algorithm - Iterative and Recursive Implementation Binary Search Algorithm is a searching algorithm used in a sorted array by repeatedly dividing the search interval in half. The idea of binary search is to use the information that the array is sorted and reduce the time complexity to O(log N). Binary Search AlgorithmConditions to apply Binary Searc
15 min read
Insertion Sort Algorithm Insertion sort is a simple sorting algorithm that works by iteratively inserting each element of an unsorted list into its correct position in a sorted portion of the list. It is like sorting playing cards in your hands. You split the cards into two groups: the sorted cards and the unsorted cards. T
9 min read
Array Data Structure Guide In this article, we introduce array, implementation in different popular languages, its basic operations and commonly seen problems / interview questions. An array stores items (in case of C/C++ and Java Primitive Arrays) or their references (in case of Python, JS, Java Non-Primitive) at contiguous
4 min read
Sorting Algorithms A Sorting Algorithm is used to rearrange a given array or list of elements in an order. For example, a given array [10, 20, 5, 2] becomes [2, 5, 10, 20] after sorting in increasing order and becomes [20, 10, 5, 2] after sorting in decreasing order. There exist different sorting algorithms for differ
3 min read