3587. Minimum Adjacent Swaps to Alternate Parity
Problem Description
You are given an array nums
of distinct integers.
In one operation, you can swap any two adjacent elements in the array.
An arrangement of the array is considered valid if the parity of adjacent elements alternates, meaning every pair of neighboring elements consists of one even and one odd number.
Return the minimum number of adjacent swaps required to transform nums
into any valid arrangement.
If it is impossible to rearrange nums
such that no two adjacent elements have the same parity, return -1
.
Intuition
To create a valid arrangement where even and odd numbers alternate, we first notice that the counts of even and odd numbers must be nearly balancedโeither equal or differing by only one. Otherwise, alternating them throughout the array is impossible.
If the balance is okay, we want to form new arrangements where the pattern is either even-odd-even-odd or odd-even-odd-even, depending on which parity starts first. By tracking the positions of even and odd numbers in the original array, we can figure out, for each valid pattern, how many moves are needed for each even and odd number to reach their target spots. Each swap moves a number one position, so the total swaps for a pattern is the sum of the distances each number must travel to get to their alternating place.
By checking both possible starting patterns (starting with even or with odd), and calculating the minimum moves for each, we determine the smallest number of adjacent swaps needed.
Solution Approach
The solution uses case analysis and a greedy approach:
-
Counting Odd and Even Numbers:
- First, count how many even and odd numbers are in the input array
nums
by iterating through it. - Store the indices of even numbers in
pos[0]
and indices of odd numbers inpos[1]
.
- First, count how many even and odd numbers are in the input array
-
Feasibility Check:
- If the counts of even and odd numbers differ by more than 1 (
abs(len(pos[0]) - len(pos[1])) > 1
), a valid alternating arrangement is impossible. In such cases, return-1
.
- If the counts of even and odd numbers differ by more than 1 (
-
Calculating Minimum Swaps:
- Define a helper function
calc(k)
, wherek
is the parity to start with (0
for even,1
for odd). - The function
calc(k)
computes the sum of the absolute differences between the current indices of elements of parityk
and their target positions in the ideal alternating arrangement (range(0, len(nums), 2)
). - For example, if the arrangement starts with even (
k=0
), the even numbers should be at positions 0, 2, 4, ..., and the function sums up how far each actual even number is from those positions.
- Define a helper function
-
Evaluating Both Arrangements:
- If the counts are equal, try both starting with even and starting with odd. Return the minimum swaps of the two patterns:
min(calc(0), calc(1))
. - If there are more even numbers, only the arrangement starting with even is valid, so return
calc(0)
. - Similarly, if there are more odd numbers, only the arrangement starting with odd is valid, so return
calc(1)
.
- If the counts are equal, try both starting with even and starting with odd. Return the minimum swaps of the two patterns:
Algorithm Summary in Steps:
- Collect indices of even and odd elements.
- Check if counts differ by at most 1.
- For each possible valid starting parity, calculate swaps needed to move all elements of that parity to their correct positions in the alternating pattern.
- Return the minimum swaps found.
All calculations use simple greedy moves and index tracking, ensuring an efficient solution.
Ready to land your dream job?
Unlock your dream job with a 2-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Consider nums = [3, 2, 4, 1]
.
Step 1: Collect Indices by Parity
- Even indices: positions where values are even
โ
nums[1]=2
,nums[2]=4
โpos[0] = [1, 2]
- Odd indices: positions where values are odd
โ
nums[0]=3
,nums[3]=1
โpos[1] = [0, 3]
So, even_count = 2
, odd_count = 2
.
Step 2: Feasibility Check
|even_count - odd_count| = |2 - 2| = 0 โค 1 We can proceed.
Step 3: Calculate Minimum Swaps
We need to try both starting parities.
(A) Start With Even (k=0
): Even, Odd, Even, Odd
-
Target even positions: 0 and 2
-
Actual even indices: [1, 2]
-
Swaps needed:
- Move from 1 to 0 โ |1-0| = 1
- Move from 2 to 2 โ |2-2| = 0 Total for evens: 1
-
Target odd positions: 1 and 3
-
Actual odd indices: [0, 3]
-
Swaps needed:
- Move from 0 to 1 โ |0-1| = 1
- Move from 3 to 3 โ |3-3| = 0 Total for odds: 1
-
Total swaps: 1 (even) + 1 (odd) = 2
(B) Start With Odd (k=1
): Odd, Even, Odd, Even
-
Target odd positions: 0 and 2
-
Actual odd indices: [0, 3]
-
Swaps needed:
- 0 โ 0 = 0
- 3 โ 2 = 1 Total: 1
-
Target even positions: 1 and 3
-
Actual even indices: [1, 2]
-
Swaps needed:
- 1 โ 1 = 0
- 2 โ 3 = 1 Total: 1
-
Total swaps: 1 (odd) + 1 (even) = 2
Step 4: Final Answer
Take the minimum from both patterns: min(2, 2) = 2
Summary:
For nums = [3, 2, 4, 1]
, arranging as [2, 3, 4, 1]
or [3, 2, 1, 4]
takes a minimum of 2 adjacent swaps to achieve alternating parity, following the outlined approach.
Solution Implementation
1class Solution:
2 def minSwaps(self, nums: list[int]) -> int:
3 # Helper function to calculate minimum swaps for a given parity (0 for even, 1 for odd)
4 def calc(parity: int) -> int:
5 # Generate pairs between target indices and current indices of chosen parity,
6 # sum of absolute differences represents minimum swaps required
7 return sum(
8 abs(target_idx - cur_idx)
9 for target_idx, cur_idx in zip(range(0, len(nums), 2), positions[parity])
10 )
11
12 # Collect indices of elements with even (0) and odd (1) parities
13 positions = [[], []]
14 for index, num in enumerate(nums):
15 positions[num & 1].append(index)
16
17 # If the counts of even and odd numbers differ by more than 1, it's impossible
18 if abs(len(positions[0]) - len(positions[1])) > 1:
19 return -1
20
21 # If there are more evens, evens must be at even indexes
22 if len(positions[0]) > len(positions[1]):
23 return calc(0)
24 # If there are more odds, odds must be at even indexes
25 if len(positions[0]) < len(positions[1]):
26 return calc(1)
27 # If both have equal count, minimum swaps needed for either arrangement
28 return min(calc(0), calc(1))
29
1import java.util.*;
2
3class Solution {
4 // pos[0] stores indices of even numbers, pos[1] stores indices of odd numbers
5 private List<Integer>[] pos = new List[2];
6 private int[] nums;
7
8 public int minSwaps(int[] nums) {
9 this.nums = nums;
10 // Initialize pos arrays to store positions of even and odd numbers
11 Arrays.setAll(pos, k -> new ArrayList<>());
12
13 // Populate pos arrays: pos[0] for even indices, pos[1] for odd indices
14 for (int i = 0; i < nums.length; ++i) {
15 pos[nums[i] % 2].add(i);
16 }
17
18 // If the difference between counts of evens and odds is more than 1, impossible to rearrange
19 if (Math.abs(pos[0].size() - pos[1].size()) > 1) {
20 return -1;
21 }
22
23 // If there are more evens, evens must occupy even positions (indexing starts at 0)
24 if (pos[0].size() > pos[1].size()) {
25 return calc(0);
26 }
27 // If there are more odds, odds must occupy even positions
28 if (pos[0].size() < pos[1].size()) {
29 return calc(1);
30 }
31 // If even and odd counts are equal, take the minimum swaps from both configuration options
32 return Math.min(calc(0), calc(1));
33 }
34
35 // Calculate total moves needed if the group indexed by 'parity'
36 // (0=even, 1=odd) occupies even indices (0, 2, 4, ...)
37 private int calc(int parity) {
38 int swaps = 0;
39 for (int i = 0; i < nums.length; i += 2) {
40 // Sum distances from current index to the target index
41 swaps += Math.abs(pos[parity].get(i / 2) - i);
42 }
43 return swaps;
44 }
45}
46
1class Solution {
2public:
3 int minSwaps(vector<int>& nums) {
4 // pos[0] stores indices of even numbers, pos[1] stores indices of odd numbers
5 vector<int> pos[2];
6 int n = nums.size();
7
8 // Partition the indices based on the parity (even or odd) of nums[i]
9 for (int i = 0; i < n; ++i) {
10 pos[nums[i] % 2].push_back(i);
11 }
12
13 // Check if it's possible to arrange in alternating parity pattern
14 if (abs(int(pos[0].size() - pos[1].size())) > 1) {
15 return -1; // Impossible case: difference between evens and odds is more than 1
16 }
17
18 // Helper Lambda to calculate the minimum swaps required when starting with parity 'parityStart'
19 auto calcSwaps = [&](int parityStart) {
20 int swapCount = 0;
21 // For every even index, match with the expected parity's stored position
22 for (int i = 0; i < n; i += 2) {
23 swapCount += abs(pos[parityStart][i / 2] - i);
24 }
25 return swapCount;
26 };
27
28 // If there are more evens, pattern must start with even
29 if (pos[0].size() > pos[1].size()) {
30 return calcSwaps(0);
31 }
32
33 // If there are more odds, pattern must start with odd
34 if (pos[0].size() < pos[1].size()) {
35 return calcSwaps(1);
36 }
37
38 // If even and odd counts equal: choose minimum swaps of starting with even or odd
39 return min(calcSwaps(0), calcSwaps(1));
40 }
41};
42
1// Function to calculate the minimum number of swaps to arrange the array
2// so that numbers with different parity (odd/even) alternate.
3function minSwaps(nums: number[]): number {
4 // Arrays to record the positions of even (index 0) and odd (index 1) numbers
5 const positions: number[][] = [[], []];
6
7 // Collect the indices of even and odd numbers
8 for (let i = 0; i < nums.length; ++i) {
9 positions[nums[i] & 1].push(i);
10 }
11
12 // If the difference in counts of even and odd numbers is greater than 1,
13 // it's not possible to rearrange them in alternating order
14 if (Math.abs(positions[0].length - positions[1].length) > 1) {
15 return -1;
16 }
17
18 // Helper function to calculate swaps needed if parity 'k' starts first
19 const calculateSwaps = (parityIndex: number): number => {
20 let swapCount = 0;
21 // For all positions where this parity should be (even indexes 0, 2, ...)
22 for (let i = 0; i < nums.length; i += 2) {
23 // Add the distance needed to move the number from its current position to the required position
24 swapCount += Math.abs(positions[parityIndex][i >> 1] - i);
25 }
26 return swapCount;
27 };
28
29 // If more even numbers, even must be at 0th index, calculate swaps accordingly
30 if (positions[0].length > positions[1].length) {
31 return calculateSwaps(0);
32 }
33
34 // If more odd numbers, odd must be at 0th index, calculate swaps accordingly
35 if (positions[0].length < positions[1].length) {
36 return calculateSwaps(1);
37 }
38
39 // If counts are equal, try both possibilities and take the minimum
40 return Math.min(calculateSwaps(0), calculateSwaps(1));
41}
42
Time and Space Complexity
-
Time Complexity:
O(n)
, wheren
is the length of the arraynums
. This is because the code iterates throughnums
once to populate thepos
lists and, for at most two calls, computessum(abs(i - j) ...)
over all positions, which in total takes linear time. -
Space Complexity:
O(n)
, since the auxiliary arrayspos[0]
andpos[1]
together store the indices of all elements innums
, consuming linear extra space.
Which of the following uses divide and conquer strategy?
Recommended Readings
Greedy Introduction div class responsive iframe iframe src https www youtube com embed WTslqPbj7I title YouTube video player frameborder 0 allow accelerometer autoplay clipboard write encrypted media gyroscope picture in picture web share allowfullscreen iframe div When do we use greedy Greedy algorithms tend to solve optimization problems Typically they will ask you to calculate the max min of some value Commonly you may see this phrased in the problem as max min longest shortest largest smallest etc These keywords can be identified by just scanning
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!