class Solution:
def smallerNumbersThanCurrent(self, nums):
# Sort the array to find the rank of each number
sorted_nums = sorted(nums)
# Use a dictionary to store the first occurrence index (count of smaller numbers)
num_to_count = {}
for i, num in enumerate(sorted_nums):
if num not in num_to_count:
num_to_count[num] = i
# Build the result using the mapping
return [num_to_count[num] for num in nums]
class Solution {
public:
vector<int> smallerNumbersThanCurrent(vector<int>& nums) {
vector<int> sorted_nums(nums);
sort(sorted_nums.begin(), sorted_nums.end());
unordered_map<int, int> num_to_count;
for (int i = 0; i < sorted_nums.size(); ++i) {
if (num_to_count.find(sorted_nums[i]) == num_to_count.end()) {
num_to_count[sorted_nums[i]] = i;
}
}
vector<int> res;
for (int num : nums) {
res.push_back(num_to_count[num]);
}
return res;
}
};
class Solution {
public int[] smallerNumbersThanCurrent(int[] nums) {
int[] sorted = nums.clone();
Arrays.sort(sorted);
Map<Integer, Integer> numToCount = new HashMap<>();
for (int i = 0; i < sorted.length; i++) {
if (!numToCount.containsKey(sorted[i])) {
numToCount.put(sorted[i], i);
}
}
int[] res = new int[nums.length];
for (int i = 0; i < nums.length; i++) {
res[i] = numToCount.get(nums[i]);
}
return res;
}
}
var smallerNumbersThanCurrent = function(nums) {
let sorted = [...nums].sort((a, b) => a - b);
let numToCount = {};
for (let i = 0; i < sorted.length; i++) {
if (numToCount[sorted[i]] === undefined) {
numToCount[sorted[i]] = i;
}
}
return nums.map(num => numToCount[num]);
};
Given an array of integers nums
, for each element nums[i]
, determine how many numbers in the array are strictly smaller than nums[i]
. The output should be an array where each index i
contains the count of numbers in nums
that are less than nums[i]
.
Constraints:
The problem at first seems to require, for every number, a count of how many numbers are less than it. A straightforward way is to use two loops: for each element, scan the entire array and count how many numbers are smaller. However, this brute-force approach has a time complexity of O(n²), which can be slow for larger arrays.
To optimize, we can consider sorting the array. Sorting arranges numbers from smallest to largest, so the position (index) of a number in the sorted array tells us how many numbers are smaller than it. But, since numbers can repeat, we need to be careful to only count the first occurrence of each unique number.
Using a mapping (like a hash map or dictionary), we can store for each unique number its first index in the sorted array. Then, for each original number, we can look up this count efficiently.
Here’s a step-by-step guide to the optimized solution:
nums
. Sorting brings all smaller numbers before larger ones.
Why use a hash map? Because it allows us to look up the count for each number in constant time, O(1), making the solution efficient.
Summary of steps:
Sample Input: nums = [8, 1, 2, 2, 3]
sorted_nums = [1, 2, 2, 3, 8]
So the mapping is: {1: 0, 2: 1, 3: 3, 8: 4}
nums[0] = 8
→ 4nums[1] = 1
→ 0nums[2] = 2
→ 1nums[3] = 2
→ 1nums[4] = 3
→ 3
Final Output: [4, 0, 1, 1, 3]
The optimized approach is much faster for larger arrays because it avoids the nested loop.
The key insight is that sorting the array reveals, for each number, how many numbers are smaller than it by its position in the sorted array. By mapping each unique number to its first occurrence index in the sorted array, we can quickly look up the answer for each element in the original array. This approach is both simple and efficient, making it an elegant solution to the problem.