977. Squares of a Sorted Array - Explanation

Problem Link

Description

You are given an integer array nums sorted in non-decreasing order, return an array of the squares of each number sorted in non-decreasing order.

Example 1:

Input: nums = [-4,-1,0,3,10]

Output: [0,1,9,16,100]

Explanation: After squaring, the array becomes [16,1,0,9,100].
After sorting, it becomes [0,1,9,16,100].

Example 2:

Input: nums = [-7,-3,2,3,11]

Output: [4,9,9,49,121]

Constraints:

  • 1 <= nums.length <= 10,000
  • -10,000 <= nums[i] <= 10,000
  • nums is sorted in non-decreasing order.

Follow up: Squaring each element and sorting the new array is very trivial, could you find an O(n) solution using a different approach?



Topics

Company Tags

Please upgrade to NeetCode Pro to view company tags.



Prerequisites

Before attempting this problem, you should be comfortable with:

  • Two Pointers Technique - Used to compare elements from both ends of the sorted array simultaneously
  • Sorting Algorithms - Understanding time complexity trade-offs between sorting vs. linear approaches
  • Absolute Values - Recognizing that negative numbers become positive when squared, affecting order

1. Sorting

Intuition

The straightforward approach is to square each element first and then sort the result. While the original array is sorted, squaring can change the order since negative numbers become positive. For example, [-4, -1, 0, 3] becomes [16, 1, 0, 9] after squaring, which needs to be sorted to [0, 1, 9, 16].

Algorithm

  1. Iterate through the array and square each element in place.
  2. Sort the array using the built-in sort function.
  3. Return the sorted array of squares.
class Solution:
    def sortedSquares(self, nums: List[int]) -> List[int]:
        for i in range(len(nums)):
            nums[i] *= nums[i]
        nums.sort()
        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. Two Pointers - I

Intuition

Since the input array is sorted, the largest squares will be at either end (the most negative or most positive values). By using two pointers at both ends, we can compare absolute values and always pick the larger square. This builds the result in descending order, which we then reverse.

Algorithm

  1. Initialize two pointers: l at the start and r at the end of the array.
  2. Create an empty result list.
  3. While l <= r:
    • Compare the squares of nums[l] and nums[r].
    • Append the larger square to the result and move the corresponding pointer inward.
  4. Reverse the result array (since we collected largest to smallest).
  5. Return the reversed result.
class Solution:
    def sortedSquares(self, nums: List[int]) -> List[int]:
        l, r, res = 0, len(nums) - 1, []

        while l <= r:
            if (nums[l] * nums[l]) > (nums[r] * nums[r]):
                res.append(nums[l] * nums[l])
                l += 1
            else:
                res.append(nums[r] * nums[r])
                r -= 1

        return res[::-1]

Time & Space Complexity

  • Time complexity: O(n)O(n)
  • Space complexity: O(n)O(n) for the output array.

3. Two Pointers - II

Intuition

This is an optimization of the previous approach that avoids the final reversal step. Instead of building the result from smallest to largest and reversing, we fill the result array from the end to the beginning. We still use two pointers to compare the absolute values at both ends, but we place each square directly in its final position.

Algorithm

  1. Create a result array of the same size as the input.
  2. Initialize l = 0, r = n - 1, and resIndex = n - 1 (pointing to the last position).
  3. While l <= r:
    • Compare the absolute values of nums[l] and nums[r].
    • Place the larger square at res[resIndex] and move the corresponding pointer.
    • Decrement resIndex.
  4. Return the result array (no reversal needed).
class Solution:
    def sortedSquares(self, nums: List[int]) -> List[int]:
        n = len(nums)
        res = [0] * n
        l, r = 0, n - 1
        res_index = n - 1

        while l <= r:
            if abs(nums[l]) > abs(nums[r]):
                res[res_index] = nums[l] * nums[l]
                l += 1
            else:
                res[res_index] = nums[r] * nums[r]
                r -= 1
            res_index -= 1

        return res

Time & Space Complexity

  • Time complexity: O(n)O(n)
  • Space complexity: O(n)O(n) for the output array.

Common Pitfalls

Assuming Squares Preserve Sorted Order

A common mistake is assuming that squaring a sorted array keeps it sorted. This is false when negative numbers are present because squaring makes them positive, potentially larger than squared positive numbers. For example, [-4, -1, 0, 3] becomes [16, 1, 0, 9], which is not sorted.

Forgetting to Handle Negative Numbers with Two Pointers

When using two pointers, comparing nums[l] and nums[r] directly instead of their absolute values or squares leads to incorrect results. Negative numbers at the left end may have larger squares than positive numbers at the right end, so always compare absolute values or squared values.