Squares of a sorted array, in order
Given an integer array nums sorted in non-decreasing order, return the squares of its
elements, also in non-decreasing order. Do it in O(n) time, without sorting the squares.
Examples
| Input | Output | Why |
|---|---|---|
nums = [-4, -1, 0, 3, 10] | [0, 1, 9, 16, 100] | |
nums = [-7, -3, 2, 3, 11] | [4, 9, 9, 49, 121] | (−3)² and 3² are both 9. |
Constraints
- 1 ≤ n ≤ 10⁴
- −10⁴ ≤ nums[i] ≤ 10⁴
- nums is sorted in non-decreasing order
Hints
Hint 1
Squaring and sorting is O(n log n). Where in the array can the largest square be?
Hint 2
The largest square comes from the most negative value or the most positive one: one of the two ends.
Hint 3
Compare the absolute values at the two ends, write the larger square into the last free slot of the result, and move that pointer inward.
Where people lose marks
- Filling from the front: the smallest square is in the middle somewhere, and finding it costs a search.
- Comparing the values rather than their absolute values, which puts −7 below 2.
- Squares of values up to 10⁴ fit a 32-bit integer (10⁸); larger inputs would need 64-bit.
Dry run on [-6,-2,0,1,4]
Read it one frame at a time, the way you would trace the code on paper in an interview. Each frame shows the state after the step it describes.
-
Step 1 / 6nums-60i-21021344jout·0·1·2·3·4i0j4
i and j at the ends; the result is filled from its last slot.
-
Step 2 / 6nums-60i-21021344jout·0·1·2·3364i0j4k4
|-6| > |4|: write -6² = 36 at out[4], move i right.
-
Step 3 / 6nums-60-21i021344jout·0·1·2163364i1j4k3
|-2| ≤ |4|: write 4² = 16 at out[3], move j left.
-
Step 4 / 6nums-60-21i0213j44out·0·142163364i1j3k2
|-2| > |1|: write -2² = 4 at out[2], move i right.
-
Step 5 / 6nums-60-2102i13j44out·01142163364i2j3k1
|0| ≤ |1|: write 1² = 1 at out[1], move j left.
-
Step 6 / 6nums-60-2102i/j1344out001142163364i2j2k0
|0| ≤ |0|: write 0² = 0 at out[0], move j left.
How to think about it
Squaring reverses the order of the negative values, so the squares are not sorted: they fall to a minimum
near zero and rise again. But the largest square is always at one of the two ends of what is left. Keep
i at the left end and j at the right end, and fill the result from position
n − 1 down to 0:
- If
|nums[i]| > |nums[j]|, the next largest square isnums[i]²: write it and moveiright. - Otherwise write
nums[j]²and movejleft.
This is the merge step of merge sort, run backwards on the two sorted halves that the negative and non-negative values form.
Complexity. Time O(n) · Space O(n) for the output
The solution, in six languages
Each one is compiled and run against the test table before it is published. Java is reviewed by hand.
def sorted_squares(nums):
n = len(nums)
out = [0] * n
i, j = 0, n - 1
for k in range(n - 1, -1, -1): # the largest remaining square is at an end
if abs(nums[i]) > abs(nums[j]):
out[k] = nums[i] * nums[i]
i += 1
else:
out[k] = nums[j] * nums[j]
j -= 1
return out#include <vector>
#include <cstdlib>
std::vector<int> solve(const std::vector<int>& nums) {
int n = (int)nums.size(), i = 0, j = n - 1;
std::vector<int> out(n);
for (int k = n - 1; k >= 0; --k) { // the largest remaining square is at an end
if (std::abs(nums[i]) > std::abs(nums[j])) { out[k] = nums[i] * nums[i]; ++i; }
else { out[k] = nums[j] * nums[j]; --j; }
}
return out;
}class Solution {
public int[] sortedSquares(int[] nums) {
int n = nums.length, i = 0, j = n - 1;
int[] out = new int[n];
for (int k = n - 1; k >= 0; k--) { // the largest remaining square is at an end
if (Math.abs(nums[i]) > Math.abs(nums[j])) { out[k] = nums[i] * nums[i]; i++; }
else { out[k] = nums[j] * nums[j]; j--; }
}
return out;
}
}function sortedSquares(nums) {
const n = nums.length, out = new Array(n);
let i = 0, j = n - 1;
for (let k = n - 1; k >= 0; k--) { // the largest remaining square is at an end
if (Math.abs(nums[i]) > Math.abs(nums[j])) { out[k] = nums[i] * nums[i]; i++; }
else { out[k] = nums[j] * nums[j]; j--; }
}
return out;
}fn solve(nums: &[i64]) -> Vec<i64> {
let n = nums.len();
let mut out = vec![0i64; n];
let (mut i, mut j) = (0usize, n - 1);
for k in (0..n).rev() { // the largest remaining square is at an end
if nums[i].abs() > nums[j].abs() { out[k] = nums[i] * nums[i]; i += 1; }
else { out[k] = nums[j] * nums[j]; if j > 0 { j -= 1; } }
}
out
}import Data.Array
solve :: [Int] -> [Int]
solve nums = go 0 (n - 1) []
where
n = length nums
a = listArray (0, n - 1) nums
-- prepend the largest remaining square, so the list ends up ascending
go i j acc
| i > j = acc
| abs (a ! i) > abs (a ! j) = go (i + 1) j (a ! i * a ! i : acc)
| otherwise = go i (j - 1) (a ! j * a ! j : acc)
Variants to try
- Apply any quadratic f(x) = ax² + bx + c instead of x²: the extreme values are still at the ends, which end depends on the sign of a.
- Without the output array: the result cannot be written in place in O(1) extra space without losing values still to be read.
Next problems
A palindrome, ignoring punctuation and case
Compare from both ends inward, stepping over anything that is not a letter or a digit. No cleaned copy of the string is needed.
Open the problem → Easy10 minMerge two sorted arrays
The step at the heart of merge sort: one pointer per array, and the smaller front value goes next.
Open the problem → Easy10 minMove the zeros to the end
One pointer reads every element, the other marks where the next non-zero belongs. The order of the non-zero values is kept.
Open the problem →Write a solution and run it against the real test table.
Keep going
A palindrome, ignoring punctuation and case
Compare from both ends inward, stepping over anything that is not a letter or a digit. No cleaned copy of the string is needed.
Open the problem → Easy10 minMerge two sorted arrays
The step at the heart of merge sort: one pointer per array, and the smaller front value goes next.
Open the problem → Easy10 minMove the zeros to the end
One pointer reads every element, the other marks where the next non-zero belongs. The order of the non-zero values is kept.
Open the problem → Two pointersThe pattern behind it
Two indices walking a sorted or paired structure, each step ruling out one candidate for good.
Read the pattern →Preparing for a real process? Quant interview preparation, or book a free 20-minute call.