Facebook Pixel

1806. Minimum Number of Operations to Reinitialize a Permutation

MediumArrayMathSimulation
Leetcode Link

Problem Description

You start with a permutation array perm of size n (where n is even) initialized as perm[i] = i for all indices from 0 to n-1.

In each operation, you create a new array arr by rearranging elements according to these rules:

  • For even indices i: take the element from the first half of perm at position i/2 and place it at arr[i]
  • For odd indices i: take the element from the second half of perm at position n/2 + (i-1)/2 and place it at arr[i]

After creating arr, you replace perm with arr and can repeat this operation.

The goal is to find the minimum number of operations needed to return the permutation back to its original state [0, 1, 2, ..., n-1].

For example, if n = 4:

  • Initial: perm = [0, 1, 2, 3]
  • After operation 1: perm = [0, 2, 1, 3] (even indices get [0, 1], odd indices get [2, 3])
  • After operation 2: perm = [0, 1, 2, 3] (back to original)
  • Answer: 2 operations

The transformation essentially splits the array into two halves and interleaves them - the first half goes to even positions and the second half goes to odd positions.

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

Intuition

The key insight is recognizing that this operation creates a specific permutation cycle. When we apply the transformation repeatedly, each element follows a deterministic path through the array positions until it returns to its original location.

Let's trace what happens to the indices during one operation:

  • Elements at positions 0, 1, 2, ..., n/2-1 move to positions 0, 2, 4, ..., n-2 (even indices)
  • Elements at positions n/2, n/2+1, ..., n-1 move to positions 1, 3, 5, ..., n-1 (odd indices)

This means we can track where any index i moves to:

  • If i < n/2: it moves to position 2*i
  • If i >= n/2: it moves to position 2*(i - n/2) + 1

Since every element follows the same transformation pattern in each operation, they all complete their cycles at the same time. The crucial observation is that elements 0 and n-1 never move (they stay at positions 0 and n-1 respectively), so we can track any other element to determine when the entire array returns to its original state.

We choose to track element 1 (which starts at index 1) because it's simple and will definitely move. We follow its position through each operation:

  • If its current position i is in the first half (i < n/2), it moves to i * 2
  • If its current position i is in the second half (i >= n/2), it moves to (i - n/2) * 2 + 1

We count how many operations it takes for element 1 to return to position 1. This count gives us the cycle length, which is the minimum number of operations needed for the entire permutation to return to its initial state.

Learn more about Math patterns.

Solution Approach

The solution implements a simulation approach to track the movement of element 1 through its cycle until it returns to its starting position.

We initialize two variables:

  • ans: counts the number of operations performed
  • i: tracks the current position of element 1 (starts at position 1)

The algorithm uses a while loop that continues until element 1 returns to position 1:

  1. Increment the operation counter: Each iteration represents one transformation operation on the entire array.

  2. Calculate the new position of element 1 based on its current position i:

    • If i < n >> 1 (element is in the first half):
      • The new position is i << 1 (equivalent to i * 2)
      • This moves the element to an even index in the new array
    • If i >= n >> 1 (element is in the second half):
      • The new position is (i - (n >> 1)) << 1 | 1
      • Breaking this down: (i - n/2) * 2 + 1
      • This moves the element to an odd index in the new array
  3. Check for completion: If i == 1, element 1 has returned to its original position, so we return the operation count.

The use of bit operations (<< for left shift and | for bitwise OR) provides efficient calculation:

  • n >> 1 is equivalent to n / 2
  • i << 1 is equivalent to i * 2
  • (i - (n >> 1)) << 1 | 1 is equivalent to (i - n/2) * 2 + 1

This approach has a time complexity of O(n) in the worst case (the cycle length cannot exceed n) and uses O(1) space since we only track a single element's position rather than simulating the entire array transformation.

Ready to land your dream job?

Unlock your dream job with a 5-minute evaluator for a personalized learning plan!

Start Evaluator

Example Walkthrough

Let's walk through the solution with n = 6.

Initial state: perm = [0, 1, 2, 3, 4, 5]

We'll track element 1 (which starts at index 1) through each operation until it returns to position 1.

Operation 1:

  • Original array: [0, 1, 2, 3, 4, 5]
  • First half [0, 1, 2] goes to even indices [0, 2, 4]
  • Second half [3, 4, 5] goes to odd indices [1, 3, 5]
  • Result: [0, 3, 1, 4, 2, 5]
  • Element 1 moves from position 1 to position 2
    • Since 1 < 3 (n/2), new position = 1 × 2 = 2

Operation 2:

  • Current array: [0, 3, 1, 4, 2, 5]
  • First half [0, 3, 1] goes to even indices
  • Second half [4, 2, 5] goes to odd indices
  • Result: [0, 4, 3, 2, 1, 5]
  • Element 1 moves from position 2 to position 4
    • Since 2 < 3, new position = 2 × 2 = 4

Operation 3:

  • Current array: [0, 4, 3, 2, 1, 5]
  • First half [0, 4, 3] goes to even indices
  • Second half [2, 1, 5] goes to odd indices
  • Result: [0, 2, 4, 1, 3, 5]
  • Element 1 moves from position 4 to position 3
    • Since 4 ≥ 3, new position = (4 - 3) × 2 + 1 = 1 × 2 + 1 = 3

Operation 4:

  • Current array: [0, 2, 4, 1, 3, 5]
  • First half [0, 2, 4] goes to even indices
  • Second half [1, 3, 5] goes to odd indices
  • Result: [0, 1, 2, 3, 4, 5] (back to original!)
  • Element 1 moves from position 3 to position 1
    • Since 3 ≥ 3, new position = (3 - 3) × 2 + 1 = 0 × 2 + 1 = 1

Element 1 has returned to position 1 after 4 operations, so the answer is 4.

The algorithm correctly tracks this cycle:

  • Start: i = 1, ans = 0
  • Step 1: i = 2, ans = 1
  • Step 2: i = 4, ans = 2
  • Step 3: i = 3, ans = 3
  • Step 4: i = 1, ans = 4 → return 4

Solution Implementation

1class Solution:
2    def reinitializePermutation(self, n: int) -> int:
3        """
4        Count the number of operations needed to return the permutation to its initial state.
5      
6        The operation transforms each element based on its position:
7        - If index i is even: new position is i // 2
8        - If index i is odd: new position is n // 2 + (i - 1) // 2
9      
10        We track position 1 since when it returns to position 1, all elements return to original positions.
11      
12        Args:
13            n: The size of the permutation array
14          
15        Returns:
16            The minimum number of operations to return to initial permutation
17        """
18        operation_count = 0
19        current_position = 1  # Track position of element originally at index 1
20      
21        while True:
22            operation_count += 1
23          
24            # Apply the inverse transformation to track where position comes from
25            if current_position < n // 2:
26                # Element came from even index: i = 2 * current_position
27                current_position = current_position * 2
28            else:
29                # Element came from odd index: i = 2 * (current_position - n//2) + 1
30                current_position = (current_position - n // 2) * 2 + 1
31          
32            # Check if we've returned to the starting position
33            if current_position == 1:
34                return operation_count
35
1class Solution {
2    public int reinitializePermutation(int n) {
3        // Count the number of operations needed
4        int operationCount = 0;
5      
6        // Track the position of element originally at index 1
7        // We use index 1 as a representative element to track the cycle
8        int currentPosition = 1;
9      
10        // Keep applying the transformation until we return to the starting position
11        while (true) {
12            // Increment operation count for each transformation
13            operationCount++;
14          
15            // Apply the permutation transformation rule:
16            // If current position is in the first half of the array
17            if (currentPosition < n / 2) {
18                // Elements in first half move to even indices: newPos = 2 * oldPos
19                currentPosition = currentPosition * 2;
20            } else {
21                // Elements in second half move to odd indices: newPos = 2 * (oldPos - n/2) + 1
22                int offsetFromMidpoint = currentPosition - (n / 2);
23                currentPosition = (offsetFromMidpoint * 2) + 1;
24            }
25          
26            // Check if we've completed the cycle (returned to position 1)
27            if (currentPosition == 1) {
28                return operationCount;
29            }
30        }
31    }
32}
33
1class Solution {
2public:
3    int reinitializePermutation(int n) {
4        // Initialize operation counter
5        int operationCount = 0;
6      
7        // Start tracking position 1 (any position except 0 would work)
8        // Position 0 always stays at 0, so we track position 1
9        int currentPosition = 1;
10      
11        // Keep applying the permutation operation until we return to starting position
12        while (true) {
13            // Increment operation counter
14            operationCount++;
15          
16            // Apply the permutation rule:
17            // If index i is even: arr[i] = perm[i / 2]
18            // If index i is odd: arr[i] = perm[n / 2 + (i - 1) / 2]
19          
20            // Check if current position is in the first half
21            if (currentPosition < (n >> 1)) {
22                // For positions in first half, the new position is doubled
23                // This corresponds to: if new position i is even, then i = 2 * currentPosition
24                currentPosition <<= 1;
25            } else {
26                // For positions in second half, calculate new odd position
27                // This corresponds to: if new position i is odd, then i = 2 * (currentPosition - n/2) + 1
28                currentPosition = ((currentPosition - (n >> 1)) << 1) | 1;
29            }
30          
31            // Check if we've returned to the starting position
32            if (currentPosition == 1) {
33                return operationCount;
34            }
35        }
36    }
37};
38
1function reinitializePermutation(n: number): number {
2    // Initialize operation counter to track number of operations performed
3    let operationCount: number = 0;
4  
5    // Start tracking position 1 (any position except 0 would work)
6    // Position 0 always stays at 0, so we track position 1
7    let currentPosition: number = 1;
8  
9    // Keep applying the permutation operation until we return to starting position
10    while (true) {
11        // Increment operation counter for each iteration
12        operationCount++;
13      
14        // Apply the permutation transformation rule:
15        // If index i is even: arr[i] = perm[i / 2]
16        // If index i is odd: arr[i] = perm[n / 2 + (i - 1) / 2]
17      
18        // Check if current position is in the first half of the array
19        if (currentPosition < (n >> 1)) {
20            // For positions in first half, the new position is doubled
21            // This corresponds to: if new position i is even, then i = 2 * currentPosition
22            currentPosition <<= 1;
23        } else {
24            // For positions in second half, calculate new odd position
25            // This corresponds to: if new position i is odd, then i = 2 * (currentPosition - n/2) + 1
26            currentPosition = ((currentPosition - (n >> 1)) << 1) | 1;
27        }
28      
29        // Check if we've returned to the starting position
30        if (currentPosition === 1) {
31            return operationCount;
32        }
33    }
34}
35

Time and Space Complexity

The time complexity is O(n) and the space complexity is O(1).

Time Complexity Analysis: The algorithm tracks the position of index 1 through a permutation cycle. In each iteration:

  • If i < n/2: the index is doubled (i = 2*i)
  • If i >= n/2: the index follows the formula i = 2*(i - n/2) + 1

The loop continues until index 1 returns to its original position. The maximum number of iterations needed is bounded by n-1 because:

  • The permutation operation creates cycles in the array positions
  • For an array of size n, the cycle length involving position 1 is at most n-1
  • This is because position 0 always stays at position 0 (forms its own cycle of length 1)

Therefore, the time complexity is O(n).

Space Complexity Analysis: The algorithm uses only a constant amount of extra space:

  • Variable ans to count iterations
  • Variable i to track the current position
  • No additional data structures are created

The space usage doesn't grow with the input size n, resulting in O(1) space complexity.

Learn more about how to find time and space complexity quickly.

Common Pitfalls

1. Incorrect Understanding of the Transformation Direction

A common mistake is confusing the forward transformation with tracking an element's movement. The problem describes how to create a new array from the current one, but when tracking a single element's cycle, we need to think about where each position's value comes FROM, not where it goes TO.

Pitfall Example:

# INCORRECT: Thinking about where position i goes to
if i % 2 == 0:  # If current position is even
    next_position = i // 2  # This is wrong!
else:  # If current position is odd
    next_position = n // 2 + (i - 1) // 2  # This is wrong!

Solution: We need the inverse mapping. If we want to know where the element at position i came from:

  • If i < n/2: It came from position 2*i (an even index in the previous array)
  • If i >= n/2: It came from position 2*(i - n/2) + 1 (an odd index in the previous array)

2. Attempting to Track All Elements Instead of One

Some might try to simulate the entire array transformation repeatedly, which is inefficient and unnecessary.

Pitfall Example:

# INEFFICIENT: Simulating entire array transformations
def reinitializePermutation(self, n: int) -> int:
    perm = list(range(n))
    original = list(range(n))
    count = 0
  
    while True:
        count += 1
        new_perm = [0] * n
        for i in range(n):
            if i % 2 == 0:
                new_perm[i] = perm[i // 2]
            else:
                new_perm[i] = perm[n // 2 + (i - 1) // 2]
        perm = new_perm
        if perm == original:
            return count

Solution: Track only one element (like element at position 1). Due to the cyclic nature of permutations, when one element returns to its original position after going through its complete cycle, all elements return to their original positions.

3. Off-by-One Errors in Index Calculations

The transformation involves careful index arithmetic that can easily lead to off-by-one errors, especially with the odd index calculation.

Pitfall Example:

# INCORRECT: Wrong calculation for odd indices
if current_position >= n // 2:
    # Missing the proper offset calculation
    current_position = 2 * current_position + 1  # Wrong!

Solution: For the second half elements (those that go to odd positions), the correct calculation is:

current_position = (current_position - n // 2) * 2 + 1

This properly accounts for the offset from the start of the second half.

4. Not Handling the Base Case Properly

Failing to recognize that we start counting from the first operation, not from zero.

Pitfall Example:

# INCORRECT: Starting count from 0 and incrementing after check
operation_count = 0
current_position = 1

while current_position != 1:  # This will fail immediately!
    # ... transformation logic ...
    operation_count += 1

Solution: Either increment the counter at the beginning of each iteration, or use a do-while pattern to ensure at least one operation is performed before checking the condition.

Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

Which of the following array represent a max heap?


Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More