905. Sort Array by Parity - Explanation

Problem Link

Description

You are given an integer array nums, move all the even integers at the beginning of the array followed by all the odd integers.

Return any array that satisfies this condition.

Example 1:

Input: nums = [3,1,2,4]

Output: [2,4,3,1]

Explanation: The outputs [4,2,3,1], [2,4,1,3], and [4,2,1,3] would also be accepted.

Example 2:

Input: nums = [0]

Output: [0]

Constraints:

  • 1 <= nums.length <= 5000.
  • 0 <= nums[i] <= 5000.


Topics

Company Tags

Please upgrade to NeetCode Pro to view company tags.



Prerequisites

Before attempting this problem, you should be comfortable with:

  • Arrays - Basic array traversal and in-place modification
  • Two Pointers Technique - Used for optimal O(n) in-place partitioning solutions
  • Bit Manipulation Basics - Using bitwise AND (num & 1) or modulo to check parity (even/odd)

1. Sorting

Intuition

We want all even numbers before odd numbers. By treating the parity (even/odd) as a sort key, we can leverage a built-in sort. Even numbers have parity 0, odd numbers have parity 1, so sorting by parity naturally places evens first.

Algorithm

  1. Sort the array using a custom comparator based on num & 1 (or num % 2).
  2. Elements with result 0 (even) come before elements with result 1 (odd).
  3. Return the sorted array.
class Solution:
    def sortArrayByParity(self, nums: List[int]) -> List[int]:
        nums.sort(key = lambda x: x & 1)
        return nums

Time & Space Complexity

  • Time complexity: O(nlogn)O(n \log n)
  • Space complexity: O(1)O(1) or O(n)O(n) depending on the sorting algorithm.

2. Array

Intuition

Instead of sorting, we can separate elements into two groups in a single pass. Collect all even numbers in one list and all odd numbers in another, then concatenate them. This avoids the overhead of comparison-based sorting.

Algorithm

  1. Create two lists: one for even numbers, one for odd numbers.
  2. Iterate through the array and add each element to the appropriate list based on its parity.
  3. Concatenate the even list followed by the odd list.
  4. Copy the result back into the original array (or return the concatenated result).
class Solution:
    def sortArrayByParity(self, nums: List[int]) -> List[int]:
        even, odd = [], []
        for num in nums:
            if num & 1:
                odd.append(num)
            else:
                even.append(num)

        idx = 0
        for e in even:
            nums[idx] = e
            idx += 1
        for o in odd:
            nums[idx] = o
            idx += 1
        return nums

Time & Space Complexity

  • Time complexity: O(n)O(n)
  • Space complexity: O(n)O(n)

3. Two Pointers - I

Intuition

We can partition the array in-place using two pointers at opposite ends. The left pointer finds odd numbers that need to move right, and the right pointer marks where odd numbers should go. When we find an odd number on the left, we swap it with whatever is on the right, effectively pushing odd numbers to the end.

Algorithm

  1. Initialize two pointers: i at the start, j at the end.
  2. While i < j:
    • If nums[i] is odd, swap it with nums[j] and decrement j.
    • Otherwise, increment i (the element is even and already in place).
  3. Return the modified array.
class Solution:
    def sortArrayByParity(self, nums: List[int]) -> List[int]:
        i, j = 0, len(nums) - 1
        while i < j:
            if nums[i] & 1:
                nums[i], nums[j] = nums[j], nums[i]
                j -= 1
            else:
                i += 1
        return nums

Time & Space Complexity

  • Time complexity: O(n)O(n)
  • Space complexity: O(1)O(1) extra space.

4. Two Pointers - II

Intuition

This approach uses a slow and fast pointer moving in the same direction. The slow pointer l tracks where the next even number should be placed. The fast pointer r scans through the array. Whenever we find an even number, we swap it to position l and advance l. This collects all even numbers at the front.

Algorithm

  1. Initialize a slow pointer l at 0.
  2. Iterate through the array with a fast pointer r:
    • If nums[r] is even, swap nums[l] with nums[r] and increment l.
  3. Return the modified array.
class Solution:
    def sortArrayByParity(self, nums: List[int]) -> List[int]:
        l = 0
        for r in range(len(nums)):
            if nums[r] % 2 == 0:
                nums[l], nums[r] = nums[r], nums[l]
                l += 1
        return nums

Time & Space Complexity

  • Time complexity: O(n)O(n)
  • Space complexity: O(1)O(1) extra space.

Common Pitfalls

Incrementing the Pointer After Swapping with the Right Boundary

In the two-pointer approach where you swap odd elements to the right, you must not increment the left pointer after a swap. The element swapped from the right side has not been checked yet and could be odd, requiring another swap.

Using Modulo on Negative Numbers

While this problem only has non-negative integers, using num % 2 can behave unexpectedly with negative numbers in some languages (returning -1 instead of 1 for odd negatives). Using bitwise AND (num & 1) is safer and more efficient for parity checking.