链接:https://leetcode.cn/problems/how-many-numbers-are-smaller-than-the-current-number/description/
思路:
最简单的思路来说,就是双重for循环进行遍历,来判断个数,
优化思路,其中一个思路就是递推 + 哈希思想,哈希到数组之后,递推加起前面的所有数字,最后减去本身。
两层for循环暴力查找,时间复杂度明显为O(n^2)
那么我们来看一下如何优化。
首先要找小于当前数字的数字,那么从小到大排序之后,该数字之前的数字就都是比它小的了。
所以可以定义一个新数组,将数组排个序。
排序之后,其实每一个数值的下标就代表这前面有几个比它小的了。
用一个哈希表hash(本题可以就用一个数组)来做数值和下标的映射。这样就可以通过数值快速知道下标(也就是前面有几个比它小的)。
此时有一个情况,就是数值相同怎么办?
例如,数组:1 2 3 4 4 4 ,第一个数值4的下标是3,第二个数值4的下标是4了。
这里就需要一个技巧了,在构造数组hash的时候,从后向前遍历,这样hash里存放的就是相同元素最左面的数值和下标了。
最后在遍历原数组nums,用hash快速找到每一个数值 对应的 小于这个数值的个数。存放在将结果存放在另一个数组中。
- class Solution {
- public int[] smallerNumbersThanCurrent(int[] nums) {
-
- int[] cnt = new int[101];
- int n = nums.length;
- for (int i = 0; i < n; i++) {
- cnt[nums[i]] ++;
- }
- for (int i = 1; i <= 100; i++) {
- cnt[i] += cnt[i - 1];
- }
- int[] ret = new int[n];
- for (int i = 0; i < n; i++) {
- ret[i] = nums[i] == 0 ? 0 : cnt[nums[i] - 1];
- }
- return ret;
-
- }
- }
- public int[] smallerNumbersThanCurrent(int[] nums) {
- Map<Integer, Integer> map = new HashMap<>(); // 记录数字 nums[i] 有多少个比它小的数字
- int[] res = Arrays.copyOf(nums, nums.length);
- Arrays.sort(res);
- for (int i = 0; i < res.length; i++) {
- if (!map.containsKey(res[i])) { // 遇到了相同的数字,那么不需要更新该 number 的情况
- map.put(res[i], i);
- }
- }
-
- for (int i = 0; i < nums.length; i++) {
- res[i] = map.get(nums[i]);
- }
-
- return res;
- }