Want Help Cracking FAANG?

(Then click this)

×
Back to Question Bank

1238. Circular Permutation in Binary Representation - Leetcode Solution

Problem Description

Given two integers, n and start, generate a permutation of all 2^n integers from 0 to 2^n - 1 such that:

  • The first element is start.
  • Each pair of consecutive elements differs by exactly one bit in their binary representations (i.e., their XOR is a power of two).
  • The permutation is circular: the last element and the first element also differ by exactly one bit.

Return any such valid permutation as a list of integers. Each number in the range 0 to 2^n - 1 must appear exactly once.

Thought Process

To solve this problem, first recognize that it asks for a circular permutation where each adjacent element (including the wrap-around from last to first) differs by a single bit. This is the definition of a Gray code sequence.

The brute-force approach would be to generate all possible permutations and check if they satisfy the bit-difference condition, but this is highly inefficient for larger n (factorial time).

Instead, we recall that a Gray code for n bits is a known sequence satisfying the adjacency property. The only twist is that the sequence must start at start, not at 0. We need to generate the Gray code and then rotate it so it starts at start.

Solution Approach

Here’s a step-by-step breakdown:

  1. Generate the Standard Gray Code:
    • The Gray code for i is i ^ (i >> 1). For all i from 0 to 2^n - 1, this produces a list where each adjacent pair differs by one bit.
  2. Adjust the Starting Point:
    • To make the sequence start at start, XOR each element in the Gray code sequence with start. This preserves the one-bit difference property, since XORing all elements by a constant shifts the sequence but doesn’t change the bit-difference property between consecutive elements.
  3. Return the Result:
    • The resulting list is a valid circular permutation starting from start and covering all numbers from 0 to 2^n - 1 exactly once.

This approach is efficient and leverages mathematical properties of Gray codes and XOR.

Example Walkthrough

Suppose n = 2 and start = 3.

Step 1: Generate standard 2-bit Gray code:

  • i = 0: 0 ^ (0 >> 1) = 0
  • i = 1: 1 ^ (1 >> 1) = 1 ^ 0 = 1
  • i = 2: 2 ^ (2 >> 1) = 2 ^ 1 = 3
  • i = 3: 3 ^ (3 >> 1) = 3 ^ 1 = 2
So the Gray code sequence is: [0, 1, 3, 2].

Step 2: XOR each element with start = 3:
  • 0 ^ 3 = 3
  • 1 ^ 3 = 2
  • 3 ^ 3 = 0
  • 2 ^ 3 = 1
The result: [3, 2, 0, 1].

Verification:
  • 3 to 2: 3 ^ 2 = 1 (one bit)
  • 2 to 0: 2 ^ 0 = 2 (one bit)
  • 0 to 1: 0 ^ 1 = 1 (one bit)
  • 1 to 3: 1 ^ 3 = 2 (one bit, wrap-around)
All adjacent pairs differ by exactly one bit.

Time and Space Complexity

Brute-force Approach:

  • Would involve generating all permutations of 2^n elements and checking each for the one-bit property.
  • Time complexity: O((2^n)!) — factorial time, infeasible for even small n.
  • Space complexity: O(2^n) to store a permutation.
Optimized Gray Code Approach:
  • Generating the Gray code: O(2^n) time, since we generate each number once.
  • XORing with start: O(2^n) time.
  • Space complexity: O(2^n) for the result list.
Conclusion: The optimized approach is linear in the size of the output, which is optimal.

Summary

This problem leverages the mathematical structure of Gray codes, which naturally satisfy the requirement that each consecutive number differs by one bit. By generating the Gray code and then XORing each element with the desired starting value, we efficiently construct a valid circular permutation in binary representation. This approach is elegant, avoids brute-force, and runs in optimal time and space.

Code Implementation

class Solution:
    def circularPermutation(self, n: int, start: int) -> List[int]:
        result = []
        for i in range(1 << n):
            result.append(start ^ (i ^ (i >> 1)))
        return result
      
class Solution {
public:
    vector<int> circularPermutation(int n, int start) {
        vector<int> result;
        int size = 1 << n;
        for (int i = 0; i < size; ++i) {
            result.push_back(start ^ (i ^ (i >> 1)));
        }
        return result;
    }
};
      
class Solution {
    public List<Integer> circularPermutation(int n, int start) {
        List<Integer> result = new ArrayList<>();
        int size = 1 << n;
        for (int i = 0; i < size; ++i) {
            result.add(start ^ (i ^ (i >> 1)));
        }
        return result;
    }
}
      
var circularPermutation = function(n, start) {
    const result = [];
    for (let i = 0; i < (1 << n); i++) {
        result.push(start ^ (i ^ (i >> 1)));
    }
    return result;
};