Problem overview
The method distinctValues receives an array of integers, nums, and returns how many different values it contains. Repeated values count once.
In the example, [1, 5, -3, 1, -4, 2, -4, 7, 7] has nine elements, but the values 1, -4 and 7 each appear twice. The different values are 1, 5, -3, -4, 2 and 7, so the answer is 6.
The statement sets a budget of O(n log n) time and O(1) extra space. A Set would be shorter, but it needs O(n) extra space. Here the idea is to get duplicates next to each other by sorting.
Approach: sort, then count the changes
The slow way is to compare each element with every element before it, which takes O(n²) time. Sorting makes that unnecessary. After sorting in ascending order, all copies of a value sit in one block. Within the sorted array, a value is new exactly when it differs from the element just before it.
For the example, the sorted array is [-4, -4, -3, 1, 1, 2, 5, 7, 7]. Walking left to right, the value changes at -3, at 1, at 2, at 5 and at 7. The first element starts the first block, so the count is 1 plus 5 changes, which is 6.
Step by step
- Sort
numsin ascending order with the comparator(a, b) => a - b. Without the comparator, numbers are compared as strings and 10 would come before 9; equal values would still be adjacent, but a numeric sort is the safe habit. - Start
distinctat 1. The first element is always a new value, so the count begins at 1. - Loop from index 1. Starting at the second element lets each element be compared with the one before it.
- Compare with the neighbour. If
nums[i]differs fromnums[i - 1], a new block starts, so add 1 todistinct. - Return
distinctafter the loop.
The solution in TypeScript
class Solution {
distinctValues(nums: number[]): number {
nums.sort((a, b) => a - b);
let distinct = 1;
for (let i = 1; i < nums.length; i++) {
if (nums[i] != nums[i - 1]) {
distinct++;
}
}
return distinct;
}
}
Details worth knowing:
letin the loop header.let ilimits the variable to the loop. The counterdistinctis declared withlettoo, because it changes.!=and!==. Both work for two numbers. In TypeScript, comparing values of the same type,!==is the usual habit because it never converts types; the lesson's code uses!=and gets the same result here.- Sorting changes the input. The caller's array ends up sorted. Copy it with
[...nums]first if the original order matters. - The sort is the expensive part. The loop adds
distinct++at mostn - 1times.
Complexity
Time: O(n log n). Sorting takes O(n log n) and the loop is one pass of O(n), so sorting dominates.
Space: O(1). The code adds only the counter and the loop index, and the sort works in place.
Edge cases and common mistakes
- All values equal.
[2, 2, 2]never enters theif, so the answer stays 1. - A single element.
[4]skips the loop and returns 1. - An empty array. This code returns 1, not 0, because the counter starts at 1. The lesson's inputs have at least one element; if an empty input were possible, a check at the top would be needed.
- Forgetting the comparator. Default string order still keeps equal numbers together, so this particular count stays right. It is still a bad habit, because the same call gives the wrong order whenever numeric order matters.
- Starting the loop at 0. Then
nums[i - 1]readsnums[-1], which isundefined, so the first element would be counted twice. - Counting the equal pairs instead. Adding 1 when values match gives the number of duplicates, not the number of distinct values.
Testing
[1, 5, -3, 1, -4, 2, -4, 7, 7]gives6.[10, 9, 9, 100]gives3.[2, 2, 2]gives1.[4]gives1.