LeetCode #977 Easy

Squares of a Sorted Array

Given a sorted array of integers, return the squares of each number, also sorted in non-decreasing order.

two-pointersarraysorting
Open on LeetCode ↗
02

Intuition

💡

You will square everything and call sort, which is O(n log n) on an array that arrived sorted — and it grates, because you can feel the input already gave you something you just threw away. The reason the linear solution is not obvious is that squaring genuinely destroys the ordering you were handed: in [-4,-1,0,3,10] the value -4 is the smallest but 16 is the second-largest square. The order is not merely disturbed, it is folded in half around zero. But notice what survives that fold: the largest magnitudes now sit at both ends of the array, and everything in between is smaller. So while you cannot read the smallest square off either end, you can always read the largest — it is whichever of the two ends squares bigger. That flips the direction of construction: compare the two ends, take the winner, and write it into the back of the result, then step that pointer inward. The invariant is that everything outside the window [l, r] has already been placed, and every value still inside it is smaller in magnitude than everything you have written so far.

03

Approach

1

See why the sorted input is not useless, just folded

A sorted array of signed integers is really two monotone runs glued together at zero: the negatives descend in magnitude from the left edge, the non-negatives ascend in magnitude to the right edge. Squaring is a magnitude function, so it maps this into a valley — largest at the ends, smallest somewhere in the middle. Once you picture the valley, the whole approach follows: the maximum is always at one of the two ends, and the minimum is at an interior point you would have to search for. So build from the maximum.

2

Compare the ends and fill the result backwards

Allocate an output array of the same length, put a left pointer at index 0, a right pointer at the last index, and a write pointer at the last output slot. Each turn, square both ends and write the larger into the write slot, then move whichever pointer you consumed one step inward and decrement the write pointer. You could compare absolute values instead of squares — same decision, and it avoids recomputing the multiplication if you care.

3

Run until the pointers cross

Loop while l <= r, using &lt;= rather than &lt; so the final single element is not dropped. Each iteration writes exactly one output slot and shrinks the window by one, so after exactly n iterations the window is empty and the output is full. Every write took the largest remaining square, so the array comes out in non-decreasing order without a single comparison sort.

04

Solution & live demo

python
1class Solution:
2 def sortedSquares(self, nums: List[int]) -> List[int]:
3 n = len(nums)
4 out = [0] * n
5 l, r, w = 0, n - 1, n - 1
6 while l <= r:
7 if nums[l] * nums[l] > nums[r] * nums[r]:
8 out[w] = nums[l] * nums[l]
9 l += 1
10 else:
11 out[w] = nums[r] * nums[r]
12 r -= 1
13 w -= 1
14 return out
05

Edge cases

All negatives, e.g. [-5,-4,-3]

The left pointer always wins, so the array is effectively reversed into the output — which is exactly right, since squaring flips the order.

All non-negatives, e.g. [1,2,3]

The right pointer always wins and the output ends up as the input squared in place.

Ties in magnitude, e.g. [-3,3]

The squares are equal so either branch may be taken; both write the same value, so the result is identical either way.

Single element

l equals r on the first turn, one value is written, the pointers cross, and the loop ends.

06

Complexity

Time
O(n)
Space
O(n)
One pass, and the O(n) space is the output array itself — the algorithm holds nothing else, and it cannot be done in place without overwriting values it still needs.