惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

S
Secure Thoughts
Recent Commits to openclaw:main
Recent Commits to openclaw:main
H
Heimdal Security Blog
SecWiki News
SecWiki News
H
Hacker News: Front Page
N
News | PayPal Newsroom
L
LINUX DO - 最新话题
N
News and Events Feed by Topic
TaoSecurity Blog
TaoSecurity Blog
AI
AI
C
Cybersecurity and Infrastructure Security Agency CISA
Scott Helme
Scott Helme
PCI Perspectives
PCI Perspectives
S
Securelist
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
Cyberwarzone
Cyberwarzone
A
Arctic Wolf
Forbes - Security
Forbes - Security
T
Tor Project blog
Spread Privacy
Spread Privacy
WordPress大学
WordPress大学
I
Intezer
Martin Fowler
Martin Fowler
Help Net Security
Help Net Security
P
Proofpoint News Feed
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Cisco Talos Blog
Cisco Talos Blog
Latest news
Latest news
博客园 - 司徒正美
W
WeLiveSecurity
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
V
V2EX
P
Palo Alto Networks Blog
Google DeepMind News
Google DeepMind News
IT之家
IT之家
阮一峰的网络日志
阮一峰的网络日志
V
Vulnerabilities – Threatpost
Jina AI
Jina AI
S
Security Affairs
Hacker News - Newest:
Hacker News - Newest: "LLM"
Simon Willison's Weblog
Simon Willison's Weblog
Project Zero
Project Zero
T
Threatpost
P
Privacy International News Feed
人人都是产品经理
人人都是产品经理
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Application and Cybersecurity Blog
Application and Cybersecurity Blog
博客园 - Franky
Hugging Face - Blog
Hugging Face - Blog
Apple Machine Learning Research
Apple Machine Learning Research

博客园 - Grandyang

[LeetCode] 1372. Longest ZigZag Path in a Binary Tree 二叉树中的最长交错路径 [LeetCode] 1371. Find the Longest Substring Containing Vowels in Even Counts 每个元音包含偶数次的最长子字符串 [LeetCode] 1370. Increasing Decreasing String 上升下降字符串 [LeetCode] 1368. Minimum Cost to Make at Least One Valid Path in a Grid 使网格图至少有一条有效路径的最小代价 [LeetCode] 1367. Linked List in Binary Tree 二叉树中的链表 [LeetCode] 1366. Rank Teams by Votes 通过投票对团队排名 [LeetCode] 1363. Largest Multiple of Three 形成三的最大倍数 [LeetCode] 1362. Closest Divisors 最接近的因数 [LeetCode] 1361. Validate Binary Tree Nodes 验证二叉树 [LeetCode] 1360. Number of Days Between Two Dates 日期之间隔几天 [LeetCode] 1359. Count All Valid Pickup and Delivery Options 有效的快递序列数目 [LeetCode] 1358. Number of Substrings Containing All Three Characters 包含所有三种字符的子字符串数目 [LeetCode] 1357. Apply Discount Every n Orders 每隔n个顾客打折 [LeetCode] 1356. Sort Integers by The Number of 1 Bits 根据数字二进制下1 的数目排序 [LeetCode] 1354. Construct Target Array With Multiple Sums 多次求和构造目标数组 [LeetCode] 1353. Maximum Number of Events That Can Be Attended 最多可以参加的会议数目 [LeetCode] 1352. Product of the Last K Numbers 最后 K 个数的乘积 [LeetCode] 1351. Count Negative Numbers in a Sorted Matrix 统计有序矩阵中的负数 [LeetCode] 1349. Maximum Students Taking Exam 参加考试的最大学生数
[LeetCode] 1365. How Many Numbers Are Smaller Than the Current Number 有多少小于当前数字的数字
Grandyang · 2024-05-29 · via 博客园 - Grandyang

Given the array nums, for each nums[i] find out how many numbers in the array are smaller than it. That is, for each nums[i] you have to count the number of valid j's such that j != i and nums[j] < nums[i].

Return the answer in an array.

Example 1:

Input: nums = [8,1,2,2,3]
Output: [4,0,1,1,3]
Explanation:
For nums[0]=8 there exist four smaller numbers than it (1, 2, 2 and 3).
For nums[1]=1 does not exist any smaller number than it.
For nums[2]=2 there exist one smaller number than it (1).
For nums[3]=2 there exist one smaller number than it (1).
For nums[4]=3 there exist three smaller numbers than it (1, 2 and 2).

Example 2:

Input: nums = [6,5,4,8]
Output: [2,1,0,3]

Example 3:

Input: nums = [7,7,7,7]
Output: [0,0,0,0]

Constraints:

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

这道题说是给了一个数组 nums,让对于数组中的每一个数字,统计出数组中有多少个数小于该数字,并组成一个数组返回。参见题目中的例子不难理解题意,虽然说这是一道 Easy 的题,但是博主还是不想用 brute force 的方法,因为对于每个数字都遍历一遍数字统计小的实在是太直接了,完全不用什么思考,而且平方级的时间复杂度,也不知道 OJ 能不能放行。这道题比较好的解题思路是用时间换空间,建立每个数字与其出现次数之间的映射,同时按照数字大小排序,那么这里用 TreeMap 这个数据结构就比较合适了。这样按顺序遍历映射对儿,比当前映射对儿的数字小的数字个数就是前面所有映射对儿的值的总和,就拿题目中的例子1来举例吧,建立的映射对儿是:

1 -> 1
2 -> 2
3 -> 1
8 -> 1

这里定义个变量 cnt 表示当前已经累加的映射值,初始化为0。当遍历到第一个映射对儿的数字1时,当前的 cnt 值就是比1小的数字个数,为0,是对的,然后此时 cnt 要加上当前映射值1。再遍历到下一个映射对儿数字2,此时 cnt 是比2小的数字个数,为1,是对的,然后此时 cnt 要加上当前映射值2。以此类推,就可以知道比每个数字小的数字个数了,为了方便的保存结果,这里用一个 HashMap 来建立数字和比其小的数字个数之间的映射,最终组成返回数组 res 的时候就直接到这个 HashMap 中去取就可以了,参见代码如下:

解法一:

class Solution {
public:
    vector<int> smallerNumbersThanCurrent(vector<int>& nums) {
        int cnt = 0;
        vector<int> res;
        map<int, int> cntMap;
        unordered_map<int, int> m;
        for (int num : nums) {
            ++cntMap[num];
        }
        for (auto a : cntMap) {
            m[a.first] = cnt;
            cnt += a.second;
        }
        for (int num : nums) {
            res.push_back(m[num]);
        }
        return res;
    }
};

当然我们也可以不用 TreeMap 和 HashMap,因为题目限定了数字的大小不超过 100,所以可以用一个大小为 101 的数字来代替 TreeMap,统计每个数字出现的个数。接下来是建立累加和数组,这样位置i上的数字 cnt[i] 就表示不小于数字i的数字个数,所以小于数字i的数字个数就是 cnt[i-1],有了累加和数字,就可以很方便的生成返回数组 res 了,参见代码如下:

解法二:

class Solution {
public:
    vector<int> smallerNumbersThanCurrent(vector<int>& nums) {
        int n = nums.size();
        vector<int> res(n);
        vector<int> cnt(101);
        for (int num : nums) {
            ++cnt[num];
        }
        for (int i = 1; i <= 100; ++i) {
            cnt[i] += cnt[i - 1];
        }
        for (int i = 0; i < n; ++i) {
            if (nums[i] == 0) continue;
            res[i] = cnt[nums[i] - 1];
        }
        return res;
    }
};

再来看一种利用二分搜索法的解法,关于二分搜索法可以参见博主之前的总结帖 LeetCode Binary Search Summary 二分搜索法小结,先将原数组排序,这样对于每个数字,查找第一个不小于该数字的位置,其坐标就是数组中小于该数字的个数,还是用例子1,来举例,排序后为 [1,2,2,3,8],对于数字3来说,第一个不小于3的数字的位置是3,同时也表示有3个数字比数字3小,参见代码如下:

解法三:

class Solution {
public:
    vector<int> smallerNumbersThanCurrent(vector<int>& nums) {
        vector<int> res, t = nums;
        sort(t.begin(), t.end());
        for (int num : nums) {
            res.push_back(binarySearch(t, num));
        }
        return res;
    }
    int binarySearch(vector<int>& nums, int num) {
        int left = 0, right = nums.size();
        while (left < right) {
            int mid = left + (right - left) / 2;
            if (nums[mid] < num) left = mid + 1;
            else right = mid;
        }
        return right;
    }
};

当然我们也可以利用 C++ 的自带函数 lower_bound 来进行二分搜索,这样就比较偷懒啦~

解法四:

class Solution {
public:
    vector<int> smallerNumbersThanCurrent(vector<int>& nums) {
        vector<int> res, t = nums;
        sort(t.begin(), t.end());
        for (int num : nums) {
            int cnt = lower_bound(t.begin(), t.end(), num) - t.begin();
            res.push_back(cnt);
        }
        return res;
    }
};

Github 同步地址:

https://github.com/grandyang/leetcode/issues/1365

类似题目:

Count of Smaller Numbers After Self

Longest Subsequence With Limited Sum

参考资料:

https://leetcode.com/problems/how-many-numbers-are-smaller-than-the-current-number

https://leetcode.com/problems/how-many-numbers-are-smaller-than-the-current-number/solutions/524996/java-beats-100-o-n/

LeetCode All in One 题目讲解汇总(持续更新中...)