题目

给你一个数组 nums,对于其中每个元素 nums[i],请你统计数组中比它小的所有数字的数目。

换而言之,对于每个 nums[i] 你必须计算出有效的 j 的数量,其中 j 满足 j != i nums[j] < nums[i]

以数组形式返回答案。

示例 1:

输入:nums = [8,1,2,2,3]
输出:[4,0,1,1,3]
解释: 
对于 nums[0]=8 存在四个比它小的数字:(1,2,2 和 3)。 
对于 nums[1]=1 不存在比它小的数字。
对于 nums[2]=2 存在一个比它小的数字:(1)。 
对于 nums[3]=2 存在一个比它小的数字:(1)。 
对于 nums[4]=3 存在三个比它小的数字:(1,2 和 2)。

示例 2:

输入:nums = [6,5,4,8]
输出:[2,1,0,3]

示例 3:

输入:nums = [7,7,7,7]
输出:[0,0,0,0]

提示:

  • 2 <= nums.length <= 500
  • 0 <= nums[i] <= 100

解答

  • 暴力解法

思路:直接复制一份数组,将复制得到的数组进行排序,然后进行遍历比较,将得到的值添加到答案数组中,最后返回答案数组。

class Solution {
public:
    vector<int> smallerNumbersThanCurrent(vector<int>& nums) {
        vector<int> nums_sorted = nums; // 复制nums数组
        sort(nums_sorted.begin(), nums_sorted.end()); // 将复制后的数组进行排序
        vector<int> results; // 初始化答案数组
        int len = nums.size(); // 得到数组的总长度
        for (int i = 0; i < len; i++) { // 进行遍历
            int result = 0; // 初始化大于nums[i]的元素的数量为0
            for (int j = 0; j < len; j++) { // 在排序后的数组中进行遍历,以便得到精确的答案
                if (nums_sorted[j] < nums[i]) {
                    result++; // 如果发现数组中有比nums[i]更小的数字,就把result进行++的操作
                }
                else{
                    break; // 否则就跳出循环(因为这是已经排序好的数组,这个元素不小于nums[i]那么之后的元素也都大于等于nums[i] 无需继续遍历
                }
            }
            results.push_back(result); // 将答案push进答案数组中
        }
        return results; // 返回答案结果
    }
};
  • 使用计数数组优化

思路:因为nums数组中元素的大小范围为0到100,所以可以设置一个统计各个数字分别有多少个的计数数组,然后利用计数数组计算整个数组中小于nums[i]的元素的个数。

class Solution {
public:
    vector<int> smallerNumbersThanCurrent(vector<int>& nums) {
        vector<int> count(101, 0); // 初始化计数数组,范围为0到100
        vector<int> results; // 初始化结果数组
        int len = nums.size(); // 获取数组长度
        
        // 统计每个数字的出现次数
        for (int i = 0; i < len; i++) {
            count[nums[i]]++; // 统计当前数字出现的次数
        }
        
        // 遍历每个数字,计算小于当前数字的元素个数
        for (int i = 0; i < len; i++) {
            int temp_num = nums[i]; // 当前数字
            int result = 0; // 小于当前数字的元素个数
            for (int j = 0; j < temp_num; j++) { // 遍历计数数组
                result += count[j]; // 累加小于当前数字的元素个数
            }
            results.push_back(result); // 将结果添加到结果数组中
        }
        
        return results; // 返回结果数组
    }
};
  • 使用计数排序和前缀和
  1. 使用计数排序:题目中给出了限制条件,数组元素的范围是0到100,因此可以使用计数排序来替代排序函数,以提高效率。创建一个大小为101的计数数组,统计每个数字的出现次数,然后计算小于每个数字的元素个数。
  2. 使用前缀和:通过累加计算计数数组,可以得到每个数字的前缀和数组。前缀和数组的每个元素表示小于等于该数字的元素个数。然后,通过访问前缀和数组即可获取小于每个元素的元素个数。
class Solution {
public:
    vector<int> smallerNumbersThanCurrent(vector<int>& nums) {
        vector<int> count(101, 0); // 初始化计数数组
        int len = nums.size();

        // 统计每个数字的出现次数
        for (int i = 0; i < len; i++) {
            count[nums[i]]++;
        }

        // 计算前缀和数组
        for (int i = 1; i <= 100; i++) {
            count[i] += count[i - 1];
        }

        vector<int> results;
        for (int i = 0; i < len; i++) {
            if (nums[i] == 0) {
                results.push_back(0); // 对于数字0,直接加入结果数组中
            } else {
                results.push_back(count[nums[i] - 1]); // 获取小于当前数字的元素个数
            }
        }

        return results;
    }
};