Leetcode 89. Gray Code

Problem Explanation

This problem is about generating a sequence of Gray code. The Gray code is a binary numeral system where two successive values only differ in one bit. Given a non-negative integer n representing the total number of bits in the code, the task is to print the sequence of gray code. Moreover, the Gray code sequence must begin with 0.

Let's consider an example where n = 2. We consider 2 bits here for binary representation.

First, we start with the sequence [0]

Then, for the first bit (i=0), we generate a mirrored version of the sequence, append the mirrored sequence to the original sequence, and add 1<<i to all the numbers in the mirrored sequence.

So for i=0: Mirrored sequence = [0]. Sequence becomes [0,0]. We add 1<<0 to the mirrored sequence to get [0, 1].

Then, for the second bit (i=1), again we generate a mirrored version of the sequence, append it to the original sequence and add 1<<i to all the numbers in the mirrored sequence.

So for i=1 Mirrored sequence is [0, 1]. Sequence becomes [0, 1, 0, 1]. We add 1<<1 to the mirrored sequence to get [0, 1, 2, 3].

Thus we get the sequence [0, 1, 3, 2] as required.

Approach Explanation

The solution leverages the property of Gray code that it is a sequence of binary numbers where two successive values differ in one bit only. To achieve this, we first start with an empty sequence and then iterate from 0 to n-1. For each iteration i, we add 1 << i to every number in the reversed sequence and append it back to the sequence. This guarantees that the new sequence is still a valid Gray Code sequence.

Python Solution

3class Solution:
4  def grayCode(self, n: int) -> list[int]:
5    ans = [0]
6    for i in range(n):
7      ans += [x | 1 << i for x in ans[::-1]]
8    return ans

This solution starts with a list that contains only one element 0. For each number i from 0 to n (exclusive), it reverses the array, ORs each element in the reversed array with 1 << i, and appends the result to the end of the array.

Java Solution

3class Solution {
4    public List<Integer> grayCode(int n) {
5        List<Integer> list = new ArrayList<>();
6        list.add(0);
7        for(int i=0; i<n; i++){
8            int size = list.size();
9            for(int k=size-1; k>=0; k--)
10                list.add(list.get(k) | 1 << i);
11        }
12        return list;
13    }

This solution follows a similar approach. Instead of a Python list, it uses Java's ArrayList. It iterates over the array from the end to the beginning, which effectively reverses the array.

Javascript Solution

3var grayCode = function(n) {
4    let ans = [0];
5    for(let i=0; i<n; i++){
6        for(let j=ans.length-1; j>=0; j--){
7            ans.push(ans[j] | 1<<i);
8        }
9    }
10    return ans;

This solution also uses the same approach. It uses JavaScript's array push method to append to the end of the array.

C++ Solution

3class Solution {
5    vector<int> grayCode(int n) {
6        vector<int> ans{0};
7        for (int i = 0; i < n; i++) {
8            for (int j = ans.size() - 1; j >= 0; j--) {
9                ans.push_back(ans[j] | 1 << i);
10            }
11        }
12        return ans;
13    }

This solution also iterates over the array from the end to the beginning just like our previous solutions. It uses std::vector::push_back() to append to the end of the array.

C# Solution

3public class Solution {
4public IList<int> GrayCode(int n) {
5    IList<int> ans = new List<int>() {0};
6    for (int i = 0; i < n; i++) {
7        for (int j = ans.Count - 1; j >= 0; j--) {
8            ans.Add(ans[j] | 1 << i);
9        }
10    }
11    return ans;

This solution follows the same approach as the ones mentioned above. It uses the Add() method from System.Collections.Generic.List<T> to append to the end of the list.Just like the previous solutions, it leverages the pattern of reversing the array and adding it back with each element OR'd with 1 << i.

In summary, generating the Gray Code sequence can be achieved using a consistent pattern of iterating over an array, reversing that array, and then performing bitwise operations on each element. This method guarantees the validity of the Gray Code sequence, where two consecutive values differ by only one bit.

Remember that the Gray Code sequence must start with '0' and must also utilize sequential integers. Therefore, the solution is to iterate from 0 to the number of bits required and at each step, reverse the sequence, append it to the original sequence, and add 1 << i to all the numbers in the mirrored sequence.

These solutions in Python, Java, JavaScript, C++, and C# all follow this approach, demonstrating the language-agnostic nature of the problem-solving process. Each language has its own method of list/array manipulation, but the fundamental approach remains the same. Different languages just provide different interfaces for list and array operations, but the underlying principles are consistent.

Therefore, when solving a programming problem, it's most important to first understand the requirement and constraints of the problem and then devise an algorithm or approach that's independent of any specific programming language. Only then should you move forward to implement your algorithm or approach in a specific language based on its syntax, data structures, and other features. By doing this, you can enhance your versatility as a software developer, making it possible for you to quickly adapt to different programming environments and paradigms.

Thus, generating a Gray Code sequence, or tackling any other algorithmic problem, can be best accomplished by a careful understanding of the problem and a language-agnostic approach to devising a solution.

Got a question? Ask the Teaching Assistant anything you don't understand.

Still not clear? Ask in the Forum,  Discord or Submit the part you don't understand to our editors.

TA 👨‍🏫