The key is to partition the array based on the sign of the integers—negative or positive—without relying on additional data structures or sorting methods that exceed the time and space constraints.
Algorithm Description
The approach uses a single pass through the array with two pointers:
- one to traverse the array and
- another to track the position where the next negative integer should be placed. Here’s how it works:
1. Initialize a pointer \( k \) to 0: This pointer \( k \) represents the index where the next negative integer should be placed. Initially, it starts at the beginning of the array (index 0).
2. Iterate through the array with pointer \( i \) from 0 to \( n-1 \): This pointer \( i \) scans each element of the array in sequence.
3. Check each element \( A[i] \):
- If \( A[i] < 0 \) (i.e., the element is negative), swap \( A[i] \) with the element at \( A[k] \), and then increment \( k \) by 1. This action moves the negative integer to the front portion of the array and advances the boundary between negatives and positives.
- If \( A[i] > 0 \) (i.e., the element is positive), do nothing and move to the next index \( i \).
Final ALGORITHM
Set k = 0.
for i = 0 to n-1 :
if A[i] < 0 ,
{ swap A[i] with A[k]
increment k
}
Return the rearranged array.
Time Complexity:
The algorithm performs a single pass through the array with \( i \) from 0 to \( n-1 \), and each swap operation is \( O(1) \). Thus, the total time complexity is \( O(n) \).
Space Complexity
Only two variables are used: \( k \) and \( i \), along with a possible temporary variable for swapping (if not using a language feature like tuple unpacking). This is a constant amount of extra space, satisfying the \( O(1) \) requirement.
Boundary Cases needed to be define for complete understanding
- Empty array (\( n = 0 \)): The loop does not execute, and the array remains empty, which is trivially correct.
- Single element (\( n = 1 \)): If the element is positive (e.g., \( [5] \)) or negative (e.g., \( [-5] \)), no swaps occur, and the array is already in the correct form.
- All positive or all negative: For \( [1, 2, 3] \), no elements are negative, so no swaps occur, and the array is unchanged (correct since there are no negatives). For \( [-1, -2, -3] \), each element is swapped with itself as \( k \) advances, leaving the array unchanged (correct since there are no positives).
Assumptions and Clarifications
The problem specifies “positive and negative integers,” implying that zeros (neither positive nor negative) are not present. If zeros were included, their placement would be ambiguous, but since the problem doesn’t address this, we assume the array contains only non-zero integers. The algorithm does not preserve the relative order of negatives or positives, which is acceptable as the problem does not require it.
Dry Run
Consider the array \( [3, -1, 4, -2, 5, -3] \):
- Initial state: \( [3, -1, 4, -2, 5, -3] \), \( k = 0 \), \( i = 0 \)
- \( i = 0 \): \( A[0] = 3 > 0 \), no swap, \( k = 0 \)
- \( i = 1 \): \( A[1] = -1 < 0 \), swap \( A[1] \) with \( A[0] \) (i.e., -1 with 3), array becomes \( [-1, 3, 4, -2, 5, -3] \), \( k = 1 \)
- \( i = 2 \): \( A[2] = 4 > 0 \), no swap, \( k = 1 \)
- \( i = 3 \): \( A[3] = -2 < 0 \), swap \( A[3] \) with \( A[1] \) (i.e., -2 with 3), array becomes \( [-1, -2, 4, 3, 5, -3] \), \( k = 2 \)
- \( i = 4 \): \( A[4] = 5 > 0 \), no swap, \( k = 2 \)
- \( i = 5 \): \( A[5] = -3 < 0 \), swap \( A[5] \) with \( A[2] \) (i.e., -3 with 4), array becomes \( [-1, -2, -3, 3, 5, 4] \), \( k = 3 \)
- Final array: \( [-1, -2, -3, 3, 5, 4] \)
The result has all negatives (\( -1, -2, -3 \)) before all positives (\( 3, 5, 4 \)), as required.
By the end of this process, all negative integers will be positioned at indices 0 through \( k-1 \), and all positive integers will be at indices \( k \) through \( n-1 \).