Problem overview
The method positiveSquares gets an array of integers, nums, and returns a new array with the square of every number above 0, in the original order. A square is the number times itself. Zero and negative numbers are left out, and the result is an empty array when nothing is above 0. The array may be empty, and every number is between -1000 and 1000.
For [3, -1, 0, 4] the result is [9, 16]. For [-5, -2, 0] it is []. For [1, 2, 3] it is [1, 4, 9].
Approach
This is two jobs: choose some numbers, then change them. filter chooses and map changes, and chaining them in that order does both in one line: nums.filter(num => num > 0).map(num => num * num).
Why the order matters
The filter must come first. Squaring first would turn -3 into 9, and 9 passes the "above 0" test, so the negative number would sneak into the result. Filtering first looks at the original numbers, so only the real positives get squared.
Step by step
- Declare
squaresas anumber[]withlet. - Start from
nums.filter(num => num > 0). The comparison is strict, so 0 is left out. - Chain
.map(num => num * num)to square each number that stayed. - Return
squares.
The solution in TypeScript
class Solution {
positiveSquares(nums: number[]): number[] {
let squares: number[] = nums.filter(num => num > 0).map(num => num * num);
return squares;
}
}
Both methods return new arrays, so nums is not changed. If no number is above 0, filter returns an empty array and map on an empty array returns an empty array, so the empty-result case needs no extra code. The same goes for an empty input.
The loop version
The same result with a loop and an if:
let squares: number[] = [];
for (let num of nums) {
if (num > 0) {
squares.push(num * num);
}
}
Both give the same answers. The chained version reads as a description: "the positive numbers, squared". For [3, -1, 0, 4], the filter step gives [3, 4] and the map step turns that into [9, 16].
Edge cases
- Empty input. There is nothing to keep, so the answer is
[]. - Only zeros and negatives.
filterdrops everything, which is the empty answer the statement asks for. - Repeated numbers. Each copy is squared, so
[2, 2]gives[4, 4]. - Size of the squares. The biggest number is 1000, whose square is 1,000,000, far below the point where a TypeScript
numberloses exact whole values (about 9 quadrillion).
Cost
The array is read once by filter and the (shorter) result once by map, so the time grows in step with the number of items. The filter step builds an intermediate array, which is fine at the sizes in this lesson.
Testing
| nums | Result |
|---|---|
[3, -1, 0, 4] | [9, 16] |
[-5, -2, 0] | [] |
[1, 2, 3] | [1, 4, 9] |
[] | [] |
These are the results of calling the method, including the empty array.
Common mistakes
- Mapping before filtering.
nums.map(num => num * num).filter(num => num > 0)keeps the squares of the negatives too: for[-3, 2]it gives[9, 4]. - Using
>= 0. That keeps 0, and the statement leaves it out. - Sorting the result. The squares keep the order of their numbers, so nothing needs sorting.
- Squaring with
^. In TypeScript^is a bitwise operator, not a power. Writenum * num(ornum ** 2).
