- Trending Categories
Data Structure
Networking
RDBMS
Operating System
Java
MS Excel
iOS
HTML
CSS
Android
Python
C Programming
C++
C#
MongoDB
MySQL
Javascript
PHP
Physics
Chemistry
Biology
Mathematics
English
Economics
Psychology
Social Studies
Fashion Studies
Legal Studies
- Selected Reading
- UPSC IAS Exams Notes
- Developer's Best Practices
- Questions and Answers
- Effective Resume Writing
- HR Interview Questions
- Computer Glossary
- Who is Who
Moser-de Bruijn Sequence
The problem statement includes printing the first N terms of the Moser−de Bruijn Sequence where N will be given in the user input.
The Moser−de Bruijn sequence is a sequence consisting of integers which are nothing but the sum of the different powers of 4 i.e. 1, 4, 16, 64 and so on.
The first few numbers of the sequence include 0, 1, 4, 5, 16, 17, 20, 21, 64.......
The sequence always starts with zero followed by the sum of different powers of 4 such as $\mathrm{4^{0}}$ i.e $\mathrm{4^{1}\:i.e\:4,}$ then sum of $\mathrm{4^{0}\:and\:4^{1}\:i.e\:5}$ and so on.
In this problem, we will be given any positive integer N and our task will be to print the Moser−de Bruijn sequence upto N terms.
Let’s understand the problem with the examples given below.
Input
N=6
Output
0 1 4 5 16 17
Explanation − The input given is 6 which means we need to print the first 6 terms of the Moser−de Bruijn sequence which is our required output.
Input
N=12
Output
0 1 4 5 16 17 20 21 64 65 68 69
Explanation − The first 12 terms of the Moser−de Bruijn sequence is our required output. We can calculate the Nth term of the sequence by adding the different powers of 4.
Let’s understand the algorithm to print the first N terms of the Moser−de Bruijn sequence in accordance with the value of N in the input.
Algorithm
By observing the numbers in the Moser−de Bruijn sequence, we can see that the numbers in the sequence follow the mathematical relation among them.
The first few numbers in the sequence are 0, 1, 4, 5, 16, 17, 20, 21, 64, 65, 68, 69, 80, 81, 84……..
The numbers in the sequence only includes distinct powers of 4 and sum of distinct powers of 4.
If we consider the position of the numbers in the sequence from 0, we can observe that M(0)=0 and M(1)=1.
And every Nth term where N is even can be given by,
$$\mathrm{M(N)=4*M(N/2)}$$
Similarly, every Nth term where N is odd can be given by,
$$\mathrm{M(N)=4*M(N/2)+1}$$
Let’s try to find out the few numbers of the Moser−de Bruijn sequence using the above relations.
$$\mathrm{M(0)=0\:\:\:M(1)=1}$$
M(2) will be equal to 4*M(N/2) since N is even in this case. So M(2)=4*1=4.
M(3) will be equal to 4*M(N/2)+1 since N is even in this case. So, M(3)=5.
Similarly,
$$\mathrm{M(4)=4*M(4/2)=4*4=16}$$
$$\mathrm{M(5)=4*M(5/2)+1=4*4+1=17}$$
We can calculate all the terms of the sequence until N using this relation. We will use the above relation among the numbers in the sequence to print the first N terms of the Moser−de Bruijn sequence.
Approach−1 (using recursion)
We will use recursion to find the ith term of the sequence using the formula discussed in the algorithm. The steps to follow to implement the recursion in our approach to print first N terms of Moser−de Bruijn sequence are:
To find the ith number of the sequence, we will create a recursive function.
In the function, we will return 0 if i=0 and 1 if i=1. For all other values of i, we will check if i is an even number or odd. If i is even, return 4*rec(i/2) whereas if i is odd, return 4*rec(i/2)+1.
We can get the value of ith term by calculating values of the i/2 th term using recursion in order to solve the sub problems included.
Iterate in a for loop from i=0 to i>N to print the first N terms of the Moser−de Bruijn sequence.
For each iteration, we will call the recursive function to get the value of ith term in the sequence and keep printing them.
Example
//C++ code to print the N terms of Moser-de Bruijn Sequence #include <bits/stdc++.h> using namespace std; //recursive function to get the Nth term of the sequence int rec(int N){ if(N==0){ //as M(0)=0 return 0; } else if(N==1){ //as M(1)=1 return 1; } else if(N&1){ //for the case when N is odd return 4*rec(N/2)+1; } else{ //for the case when N is even return 4*rec(N/2); } } //to print the first N terms of the sequence void print_sequence(int N){ //for printing each term upto N using the rec() function for(int i=0;i<N;i++){ cout<<rec(i)<<" "; } } int main() { int N; //for input value N=22; print_sequence(N); //calling the function return 0; }
Output
0 1 4 5 16 17 20 21 64 65 68 69 80 81 84 85 256 257 260 261 272 273
Approach−2 (Dynamic Programming)
As we all know that dynamic programming is an optimised solution to the problems solved using recursion. Therefore, in order to optimise the above approach we will use the concept of dynamic programming to print the first N terms of the Moser−de Bruijn sequence.
Here, we will keep storing the values of ith term in an array of N so that we don’t need to calculate the values of repeating sub problems for ith number in the sequence.
The steps to implement dynamic programming in the approach to print first N terms of Moser−de Bruijn sequence are given below:
We will make a vector of size N to store the first N terms of the sequence.
In order to store the numbers in the array, we will make a function where we will find the ith number of the sequence using the formula discussed in the algorithm section.
Once the vector is being updated up to N terms of the sequence we will print the numbers stored in the vector by iterating in the for loop from i=0 to i<N which will be the first N terms of the Moser−de Bruijn sequence.
Example
//C++ code to print the first N terms of Moser-de Bruijn Sequence #include <bits/stdc++.h> using namespace std; //function to update the vector using dp void calculate_numbers(vector<int>& dp, int N){ dp[0]=0; //as M(0)=0 dp[1]=1; //M(1)=1 for(int i=2;i<N;i++){ if((i&1) == 0){ //if i is even dp[i]=4*dp[i/2]; } else{ //if i is odd dp[i]=4*dp[i/2]+1; } } } //function to print the first N terms of the Moser-de Bruijn sequence void print_sequence(vector<int>& dp, int N){ for(int i=0;i<N;i++){ cout<<dp[i]<<" "; } } int main() { int N; //for taking input N=35; vector<int> dp(N,0); //to store first N terms of the sequence //calling the function to update the array up to N calculate_numbers(dp,N); //to print the sequence print_sequence(dp,N); return 0; }
Output
0 1 4 5 16 17 20 21 64 65 68 69 80 81 84 85 256 257 260 261 272 273 276 277 320 321 324 325 336 337 340 341 1024 1025 1028
Time complexity: O(N) because we iterate in a for loop for N times to update N terms of the sequence.
Space complexity: O(N) as we used a vector of size N to store the numbers of the sequence.
Conclusion
The concept of the Moser−de Bruijn sequence was discussed in the article. We discussed the algorithm to find any Nth term of the sequence using the mathematical relation among the numbers which we implement in our approach in C++ using recursion and dynamic programming both to make you understand better.
I hope you find this article helpful in clearing all your concepts regarding the topic.