2149. Rearrange Array Elements by Sign
Problem Description
You are given an integer array nums
with an even length. The array contains an equal number of positive and negative integers.
Your task is to rearrange the array so that it satisfies these three conditions:
-
Alternating signs: Every consecutive pair of integers must have opposite signs (positive followed by negative, or negative followed by positive)
-
Preserve relative order: Among all positive integers, they should appear in the same order as they were in the original array. The same rule applies to negative integers - their relative order must be maintained
-
Start with positive: The rearranged array must begin with a positive integer
For example, if nums = [3, 1, -2, -5, 2, -4]
:
- The positive integers in order are:
[3, 1, 2]
- The negative integers in order are:
[-2, -5, -4]
- The result would be:
[3, -2, 1, -5, 2, -4]
The solution uses a two-pointer approach where even indices (0, 2, 4, ...) are filled with positive numbers and odd indices (1, 3, 5, ...) are filled with negative numbers. This ensures the alternating pattern while maintaining the relative order of elements with the same sign.
Intuition
Since we need to create an alternating pattern of positive and negative numbers while preserving their relative order, we can think about where each type of number should go in the final array.
Given that the array must start with a positive number and alternate signs, we can deduce a pattern:
- Position 0: positive
- Position 1: negative
- Position 2: positive
- Position 3: negative
- And so on...
This means all even indices (0, 2, 4, ...) should contain positive numbers, and all odd indices (1, 3, 5, ...) should contain negative numbers.
The key insight is that we don't need to sort or compare elements - we just need to place them in the correct positions. Since we want to preserve the relative order within each sign group, we can simply iterate through the original array once and place each element in the next available position of its type.
We can use two pointers to track the next available position for each sign:
- Pointer
i
starts at 0 and moves by 2 each time (0, 2, 4, ...) for positive numbers - Pointer
j
starts at 1 and moves by 2 each time (1, 3, 5, ...) for negative numbers
As we encounter each number in the original array, we check its sign and place it at the corresponding pointer's position, then advance that pointer by 2. This ensures both the alternating pattern and the preservation of relative order within each sign group.
Learn more about Two Pointers patterns.
Solution Approach
The solution implements a two-pointer technique to efficiently rearrange the array in a single pass.
Step-by-step implementation:
-
Initialize the result array: Create an array
ans
of the same length asnums
to store the rearranged elements.ans = [0] * len(nums)
-
Set up two pointers:
- Initialize
i = 0
to track positions for positive numbers (even indices) - Initialize
j = 1
to track positions for negative numbers (odd indices)
i, j = 0, 1
- Initialize
-
Single-pass placement: Iterate through each element
x
in the original arraynums
:- If
x > 0
(positive number):- Place it at
ans[i]
- Move
i
forward by 2 to the next even index (i += 2
)
- Place it at
- If
x < 0
(negative number):- Place it at
ans[j]
- Move
j
forward by 2 to the next odd index (j += 2
)
- Place it at
for x in nums: if x > 0: ans[i] = x i += 2 else: ans[j] = x j += 2
- If
-
Return the result: After processing all elements,
ans
contains the properly rearranged array.
Why this works:
- By incrementing pointers by 2, we ensure positive numbers only go to even indices (0, 2, 4, ...) and negative numbers only go to odd indices (1, 3, 5, ...)
- Processing elements in their original order naturally preserves the relative order within each sign group
- The alternating pattern is guaranteed by the index assignment strategy
Time Complexity: O(n)
- single pass through the array
Space Complexity: O(n)
- for the result array (not counting it as extra space since it's required for the output)
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 nums = [3, 1, -2, -5, 2, -4]
:
Initial Setup:
- Create result array:
ans = [_, _, _, _, _, _]
(length 6) - Set pointers:
i = 0
(for positive numbers),j = 1
(for negative numbers)
Processing each element:
-
Element: 3 (positive)
- Place at
ans[i]
βans[0] = 3
- Result:
ans = [3, _, _, _, _, _]
- Update:
i = 0 + 2 = 2
- Place at
-
Element: 1 (positive)
- Place at
ans[i]
βans[2] = 1
- Result:
ans = [3, _, 1, _, _, _]
- Update:
i = 2 + 2 = 4
- Place at
-
Element: -2 (negative)
- Place at
ans[j]
βans[1] = -2
- Result:
ans = [3, -2, 1, _, _, _]
- Update:
j = 1 + 2 = 3
- Place at
-
Element: -5 (negative)
- Place at
ans[j]
βans[3] = -5
- Result:
ans = [3, -2, 1, -5, _, _]
- Update:
j = 3 + 2 = 5
- Place at
-
Element: 2 (positive)
- Place at
ans[i]
βans[4] = 2
- Result:
ans = [3, -2, 1, -5, 2, _]
- Update:
i = 4 + 2 = 6
- Place at
-
Element: -4 (negative)
- Place at
ans[j]
βans[5] = -4
- Result:
ans = [3, -2, 1, -5, 2, -4]
- Update:
j = 5 + 2 = 7
- Place at
Final Result: [3, -2, 1, -5, 2, -4]
Notice how:
- Positive numbers
[3, 1, 2]
maintained their original order and occupy even indices[0, 2, 4]
- Negative numbers
[-2, -5, -4]
maintained their original order and occupy odd indices[1, 3, 5]
- The array alternates between positive and negative values throughout
Solution Implementation
1class Solution:
2 def rearrangeArray(self, nums: List[int]) -> List[int]:
3 # Initialize result array with the same length as input
4 result = [0] * len(nums)
5
6 # Set up two pointers:
7 # positive_index starts at 0 (even indices for positive numbers)
8 # negative_index starts at 1 (odd indices for negative numbers)
9 positive_index = 0
10 negative_index = 1
11
12 # Iterate through each number in the input array
13 for number in nums:
14 if number > 0:
15 # Place positive numbers at even indices (0, 2, 4, ...)
16 result[positive_index] = number
17 positive_index += 2
18 else:
19 # Place negative numbers at odd indices (1, 3, 5, ...)
20 result[negative_index] = number
21 negative_index += 2
22
23 return result
24
1class Solution {
2 public int[] rearrangeArray(int[] nums) {
3 // Create result array with same length as input
4 int[] result = new int[nums.length];
5
6 // Initialize pointers for positive and negative number positions
7 // positiveIndex starts at 0 (even indices: 0, 2, 4, ...)
8 // negativeIndex starts at 1 (odd indices: 1, 3, 5, ...)
9 int positiveIndex = 0;
10 int negativeIndex = 1;
11
12 // Iterate through each number in the input array
13 for (int number : nums) {
14 if (number > 0) {
15 // Place positive number at even index
16 result[positiveIndex] = number;
17 // Move to next even position
18 positiveIndex += 2;
19 } else {
20 // Place negative number at odd index
21 result[negativeIndex] = number;
22 // Move to next odd position
23 negativeIndex += 2;
24 }
25 }
26
27 return result;
28 }
29}
30
1class Solution {
2public:
3 vector<int> rearrangeArray(vector<int>& nums) {
4 // Create result array with the same size as input
5 vector<int> result(nums.size());
6
7 // Initialize pointers for positive and negative positions
8 // positiveIndex: tracks even indices (0, 2, 4, ...) for positive numbers
9 // negativeIndex: tracks odd indices (1, 3, 5, ...) for negative numbers
10 int positiveIndex = 0;
11 int negativeIndex = 1;
12
13 // Iterate through each number in the input array
14 for (int currentNum : nums) {
15 if (currentNum > 0) {
16 // Place positive number at even index
17 result[positiveIndex] = currentNum;
18 positiveIndex += 2; // Move to next even position
19 } else {
20 // Place negative number at odd index
21 result[negativeIndex] = currentNum;
22 negativeIndex += 2; // Move to next odd position
23 }
24 }
25
26 return result;
27 }
28};
29
1/**
2 * Rearranges an array of integers such that positive and negative numbers
3 * alternate, starting with a positive number.
4 *
5 * @param nums - Array containing equal number of positive and negative integers
6 * @returns Rearranged array with alternating positive and negative numbers
7 */
8function rearrangeArray(nums: number[]): number[] {
9 // Initialize result array with the same length as input
10 const result: number[] = new Array(nums.length);
11
12 // positiveIndex starts at 0 (even indices), negativeIndex starts at 1 (odd indices)
13 let positiveIndex: number = 0;
14 let negativeIndex: number = 1;
15
16 // Iterate through each number in the input array
17 for (const currentNumber of nums) {
18 if (currentNumber > 0) {
19 // Place positive numbers at even indices (0, 2, 4, ...)
20 result[positiveIndex] = currentNumber;
21 positiveIndex += 2;
22 } else {
23 // Place negative numbers at odd indices (1, 3, 5, ...)
24 result[negativeIndex] = currentNumber;
25 negativeIndex += 2;
26 }
27 }
28
29 return result;
30}
31
Time and Space Complexity
The time complexity is O(n)
, where n
is the length of the array nums
. The algorithm iterates through the input array exactly once using a single for loop, performing constant-time operations (comparison and assignment) for each element.
The space complexity is O(n)
, where n
is the length of the array nums
. The algorithm creates a new array ans
of the same size as the input array to store the rearranged elements. The additional variables i
and j
use only O(1)
extra space, so the overall space complexity is dominated by the ans
array.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Assuming the array can start with either sign
A common mistake is not carefully reading that the output must start with a positive integer. Some might implement a solution that starts with whichever sign appears first in the input.
Incorrect approach:
# Wrong: This might start with negative if first element is negative
def rearrangeArray(self, nums):
result = []
pos = [x for x in nums if x > 0]
neg = [x for x in nums if x < 0]
for i in range(len(pos)):
result.append(pos[i])
result.append(neg[i])
return result
Solution: Always place positive numbers at even indices starting from 0, ensuring the first element is positive.
2. Using separate arrays and multiple passes
While technically correct, using separate arrays for positive and negative numbers requires multiple passes and extra space, making it less efficient.
Inefficient approach:
def rearrangeArray(self, nums):
positives = []
negatives = []
# First pass: separate numbers
for num in nums:
if num > 0:
positives.append(num)
else:
negatives.append(num)
# Second pass: merge alternately
result = []
for i in range(len(positives)):
result.append(positives[i])
result.append(negatives[i])
return result
Solution: Use the two-pointer approach with direct placement to achieve O(n) time with a single pass.
3. Forgetting to handle the equal count constraint
The problem guarantees equal numbers of positive and negative integers. However, if you're adapting this solution for a different problem, not verifying this constraint could lead to index out of bounds errors.
Potential issue if constraint wasn't guaranteed:
# This would fail if positive and negative counts differ positive_index = 0 negative_index = 1 # If we have more positives than negatives, negative_index would go out of bounds
Solution: For this specific problem, the constraint is guaranteed. For general cases, add validation or handle unequal counts appropriately.
4. Incrementing pointers by 1 instead of 2
A subtle but critical error is incrementing the pointers by 1 instead of 2, which would cause elements to overwrite each other.
Wrong increment:
if number > 0: result[positive_index] = number positive_index += 1 # Wrong! Should be += 2
Solution: Always increment by 2 to skip to the next appropriate position (next even index for positives, next odd index for negatives).
A heap is a ...?
Recommended Readings
Tech Interview Pattern Two Pointers Introduction If you prefer videos here's a super quick introduction to Two Pointers div class responsive iframe iframe src https www youtube com embed xZ4AfXHQ1VQ title YouTube video player frameborder 0 allow accelerometer autoplay clipboard write encrypted media gyroscope picture in picture allowfullscreen iframe div Two pointers is a common interview
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!