Circular Permutation in Binary Representation
MedPrompt
Given 2 integers n and start. Your task is return any permutation p of (0,1,2.....,2^n -1) such that :
p[0] = startp[i]andp[i+1]differ by only one bit in their binary representation.p[0]andp[2^n -1]must also differ by only one bit in their binary representation.
Example 1:
Input: n = 2, start = 3
Output: [3,2,0,1]
Explanation: The binary representation of the permutation is (11,10,00,01).
All the adjacent element differ by one bit. Another valid permutation is [3,1,0,2]Example 2:
Input: n = 3, start = 2
Output: [2,6,7,5,4,0,1,3]
Explanation: The binary representation of the permutation is (010,110,111,101,100,000,001,011).
Constraints:
1 <= n <= 160 <= start < 2 ^ n
Approaches
3 approaches with complexity analysis and trade-offs.
This approach uses a classic backtracking algorithm to explore all possible permutations. It builds the sequence one number at a time, ensuring each new number satisfies the single-bit-difference rule. If it reaches a dead end, it backtracks to try another path. This is conceptually a search for a Hamiltonian Path in an n-dimensional hypercube graph.
Algorithm
- Initialize a
resultlist withstart. - Initialize a
visitedset withstart. - Define a recursive function
solve():- If
result.size() == 2^n:- Check if
result.get(0)andresult.get(result.size() - 1)differ by one bit. - If they do, return
true. Otherwise, returnfalse.
- Check if
- Get
last = result.get(result.size() - 1). - For
ifrom0ton-1:- Calculate
next = last ^ (1 << i). - If
nextis not invisited:- Add
nexttoresultandvisited. - If
solve()returnstrue, returntrue. - Backtrack: remove
nextfromresultandvisited.
- Add
- Calculate
- Return
false.
- If
- Call
solve()to populate theresultlist.
Walkthrough
The algorithm starts with a list containing only the start element. A visited set is used to keep track of numbers that are already part of the sequence to avoid cycles and redundant computations. A recursive function is defined to build the permutation. In each recursive call, it takes the last element added to the sequence and tries to find a valid next element by flipping each of its n bits one by one. A candidate is valid if it hasn't been visited yet. If a valid candidate is found, it's added to the sequence, and the function calls itself. If the recursive call fails to find a complete path, the candidate is removed (this is the backtracking step). The base case for the recursion is when the sequence length reaches 2^n. At this point, a final check is performed to ensure the circular condition (the first and last elements differ by one bit) is met. If so, a solution has been found.
class Solution { public List<Integer> circularPermutation(int n, int start) { List<Integer> result = new ArrayList<>(); Set<Integer> visited = new HashSet<>(); result.add(start); visited.add(start); backtrack(n, (1 << n), result, visited); return result; } private boolean backtrack(int n, int totalSize, List<Integer> result, Set<Integer> visited) { if (result.size() == totalSize) { int first = result.get(0); int last = result.get(result.size() - 1); int xor = first ^ last; // Check if xor is a power of 2 return (xor > 0) && ((xor & (xor - 1)) == 0); } int last = result.get(result.size() - 1); for (int i = 0; i < n; i++) { int next = last ^ (1 << i); if (!visited.contains(next)) { visited.add(next); result.add(next); if (backtrack(n, totalSize, result, visited)) { return true; } // Backtrack visited.remove(next); result.remove(result.size() - 1); } } return false; }}Complexity
Time
O(n * 2^n). The recursion can have a depth of `2^n`. At each step, we explore up to `n` possible next elements by flipping each bit of the current number.
Space
O(2^n). This space is used for the recursion stack (which can go up to `2^n` deep), the `visited` set, and the `result` list.
Trade-offs
Pros
It's a general approach for path-finding problems and is guaranteed to find a solution if one exists.
Conceptually straightforward for those familiar with recursion and backtracking.
Cons
Significantly slower than other approaches due to its exponential nature.
May result in a 'Time Limit Exceeded' error for larger values of
n(e.g.,n=16).
Solutions
Solution
int gray ( x ) { return x ^ ( x >> 1 ); }Video walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.