1806. Minimum Number of Operations to Reinitialize a Permutation
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 ofperm
at positioni/2
and place it atarr[i]
- For odd indices
i
: take the element from the second half ofperm
at positionn/2 + (i-1)/2
and place it atarr[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.
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 positions0, 2, 4, ..., n-2
(even indices) - Elements at positions
n/2, n/2+1, ..., n-1
move to positions1, 3, 5, ..., n-1
(odd indices)
This means we can track where any index i
moves to:
- If
i < n/2
: it moves to position2*i
- If
i >= n/2
: it moves to position2*(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 toi * 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 performedi
: tracks the current position of element1
(starts at position1
)
The algorithm uses a while loop that continues until element 1
returns to position 1
:
-
Increment the operation counter: Each iteration represents one transformation operation on the entire array.
-
Calculate the new position of element
1
based on its current positioni
:- If
i < n >> 1
(element is in the first half):- The new position is
i << 1
(equivalent toi * 2
) - This moves the element to an even index in the new array
- The new position is
- 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
- The new position is
- If
-
Check for completion: If
i == 1
, element1
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 ton / 2
i << 1
is equivalent toi * 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 EvaluatorExample 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 formulai = 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 mostn-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 position2*i
(an even index in the previous array) - If
i >= n/2
: It came from position2*(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.
Which of the following array represent a max heap?
Recommended Readings
Math for Technical Interviews How much math do I need to know for technical interviews The short answer is about high school level math Computer science is often associated with math and some universities even place their computer science department under the math faculty However the reality is that you
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Want a Structured Path to Master System Design Too? Don’t Miss This!