JS leetcode 有多少小于当前数字的数字 解题分析,你应该了解的桶排序
壹 ❀ 引
刷题其实一直没断,只是这两天懒得整理题目...那么今天来记录一道前天做的题,题目本身不难,不过拓展起来还是有些东西可以讲,题目来自leetcode有多少小于当前数字的数字,题目描述如下:
给你一个数组 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
要求很简单,对于数组中每个元素,统计比它要小的元素的个数,我们来尝试解答它。
贰 ❀ 解题思路
那么我首先想到的比较暴力的做法自然是使用双循环嵌套了,设置一个用于统计个数的变量,外层循环每次取一个元素出来,依次跟内层循环的每个元素对比,只要满足条件,让计数变量自增。
说干就干,实现是这样:
贰 ❀ 壹 使用双循环
/**
* @param {number[]} nums
* @return {number[]}
*/
var smallerNumbersThanCurrent = function (nums) {
let ans = [],
len = nums.length;
// 每次取一位出来作为参照
for (let i = 0; i < len; i++) {
// 计数变量
let sum = 0;
for (let j = 0; j < len; j++) {
if (nums[i] > nums[j]) {
++sum;
};
};
ans.push(sum);
};
return ans;
};
贰 ❀ 贰 排序加indexOf
在实现后,我脑中有了一个想法,能不能把数组排个序,比如[8,1,2,2,3]
排序后是[1,2,2,3,8]
,这样我能知道每个元素前有几个元素,不就是我们想要的答案了。
当然这只是一个模糊的想法,有两个问题需要解决,一是我怎么知道有几个元素比当前元素小,特别是当元素相同的时候,比如[7,7,7,8]
。
比第一个7要小的数为0个,第二个7也是0个,第三个7还是0个,而第四个8是三个,0,0,0,3。这不是就在用indexOf
获取索引吗,管你元素相不相同,相同获取第一个数字的索引就行了。
第二个问题是,一旦数组被我们排序,虽然能得到对应的个数,但这个个数的顺序也被打乱了,怎么还原呢?别忘了我们还可以拷贝一份数组。那么到这里我们来看看第二种实现:
/**
* @param {number[]} nums
* @return {number[]}
*/
var smallerNumbersThanCurrent = function (nums) {
let ans = [],
// 拷贝一份数组,用于维持ans查询结果顺序
nums_ = JSON.parse(JSON.stringify(nums));
//将nums排序好
nums = nums.sort((a, b) => a - b);
nums_.forEach(item => {
ans.push(nums.indexOf(item));
});
return ans;
};
在评论区,我看到有用户在拷贝数组时使用的是[].concat(nums)
,比如:
let arr = [1,2,3];
let arr_ = [].concat(arr);
arr_;//[1,2,3]
那么有个问题,concat
是浅拷贝还是深拷贝?如果我们修改上面例子中的arr,你会发现互不影响:
arr.push(4);
arr_;//[1,2,3]
这能说明concat
是深拷贝吗?其实在MDN中关于concat
描述很清楚,此方法会依次拷贝目标数组中每个元素,而对于元素类型不同做不同决策。如果元素是简单类型,则直接复制元素,但如果元素是对象类型,而是拷贝对象的引用,所以我们可以来看一个对象数组的类型,比如:
let arr = [1,[2,3],4];
let arr_ = [].concat(arr);
arr[1].push(1);
arr_;//[1,[2,3,1],4]
那么关于此方案说到这了。当然除了以上两种方案外,还有一种是官方提到的计数排序+求前缀和的做法。当时相比官方所说的计数排序,我觉得更像桶排序,由于这两种排序十分类似,我暂时未能分清他们,所以这里暂且叫桶排序吧。
我知道第一次听说桶排序的同学一定会很陌生,没事,我们先来简单介绍它,以[3,2,2,1,4]
为例。
由于数组中最大元素是4,所以我们建立五个用于装元素的桶,桶默认值都是0,那为啥是五个?因为数组默认索引是从0开始的,0-1-2-3-4,这不是5个桶吗?
现在我们开始遍历[3,2,2,1,4]
,将数字丢到对应索引的桶中,每丢一个进去让桶的初始值自增1,像这样:
现在我们得到了一个装满数字的桶,因为他也是一个数组,遍历桶,比如桶1的数量为1,输出1个1,桶2数量是2,所以输出2个2,以此类推:
你看,我们不就得到了一个已经排序好的数组了,让我们尝试实现它(注意,这并非官方的桶排序,我只是按照这个思路去实现它)。
// 非正式桶排序
function bucketSort(nums) {
// 找出最大元素
let max = Math.max(...nums),
// 创建桶
bucket = new Array(max + 1).fill(0),
ans = [];
// 统计对应桶位元素数量
nums.forEach(ele => {
bucket[ele]++;
});
for (var i = 0; i < bucket.length; i++) {
while (bucket[i] > 0) {
ans.push(i);
bucket[i]--;
};
};
return ans;
};
bucketSort([3, 2, 2, 1]); //[1,2,2,3]
OK,知道了这个怎么能用于解题呢?仔细想想,当我们桶排序后,对应每个桶的数量,不就是我们希望要的数字吗,比如上方图解中:
比桶1小的元素位0个,也就是bucket[1-1]
个。
比桶2小的元素有1个,也就是bucket[1-1]+bucket[2-1]
个。
比桶3小的元素有3个,也就是bucket[3-1]+bucket[3-2]+bucket[3-3]
个。
比桶4小的元素有4个,也就是bucket[4-1]+bucket[4-2]+bucket[4-3]+bucket[4-4]
个。
当然有个特例,因为桶0是一个,不会有比它小的元素了,所以比它小的一定是0个。
这也是我们在前面说官方用计数排序加求前缀和做法,为何要求前缀和的原因。我知道这有点绕,静下心仔细想想,这只是用了桶排序统计了元素的个数,元素成了桶数组的下标,顺带求了数量的和。
现在让我们实现它,像这样:
/**
* @param {number[]} nums
* @return {number[]}
*/
var smallerNumbersThanCurrent = function(nums) {
let ans = [],
max = Math.max(...nums),
len = nums.length;
// 由于i范围是0 <= nums[i] <= 100,因此创建101个桶
let bucket = new Array(max + 1).fill(0);
// 将元素装到对应的桶
for (let i = 0; i < len; i++) {
// 数字每出现一次,桶的统计数量就加1
bucket[nums[i]]++;
};
// 求n项出现的次数和,考虑越界情况,此处i从1开始
for (let i = 1; i <= 100; i++) {
bucket[i] += bucket[i - 1]
};
// nums中元素对应了桶的索引,索引非0取前一位,索引为0说明没有比它小的,直接赋予0
for (let i = 0; i < len; i++) {
nums[i] ? ans[i] = bucket[nums[i] - 1] : ans[i] = 0
};
return ans;
};
那么关于本题就分析到这里了。
JS leetcode 有多少小于当前数字的数字 解题分析,你应该了解的桶排序的更多相关文章
- LeetCode:移除K位数字【402】
LeetCode:移除K位数字[402] 题目描述 给定一个以字符串表示的非负整数 num,移除这个数中的 k 位数字,使得剩下的数字最小. 注意: num 的长度小于 10002 且 ≥ k. nu ...
- js正则表达式,判断字符串是否以数字组结尾,并取出结尾的数字
js正则表达式,判断字符串是否以数字组结尾,并取出结尾的数字 <!DOCTYPE html> <html> <head> <meta charset=&quo ...
- js 关于字符串转数字及数字保留位数的控制
1.parseInt()和parseFloat()两个转换函数,将字符串转换成相应的数字. 1.parseInt() parseInt进行转换时,将字符串转成相应的整数.浮点数以后的数字都不要了. p ...
- HDU 4352 区间的有多少个数字满足数字的每一位上的数组成的最长递增子序列为K(数位DP+LIS)
题目:区间的有多少个数字满足数字的每一位上的数组成的最长递增子序列为K 思路:用dp[i][state][j]表示到第i位状态为state,最长上升序列的长度为k的方案数.那么只要模拟nlogn写法的 ...
- js正则表达式限制文本框只能输入数字,小数点,英文字母
1.文本框只能输入数字代码(小数点也不能输入)<input onkeyup="this.value=this.value.replace(/\D/g,'')" onafter ...
- Leetcode之二分法专题-374. 猜数字大小(374. Guess Number Higher or Lower)
Leetcode之二分法专题-374. 猜数字大小(374. Guess Number Higher or Lower) 我们正在玩一个猜数字游戏. 游戏规则如下:我从 1 到 n 选择一个数字. 你 ...
- js运算【按位非】~ (index = ~~this.userIndex)(~~ 双破折号 如果是数字返回数字,如果不是数字 返回0)
index = ~~this.userIndex ~~ 双破折号 如果是数字返回数字,如果不是数字 返回0 这个运算符有点意思:按位非[~] 先来几个例子: ~undefined: -1 ~false ...
- Input 只能输入数字,数字和字母等的正则表达式
JS只能输入数字,数字和字母等的正则表达式 1.文本框只能输入数字代码(小数点也不能输入) <input onkeyup="this.value=this.value.replace( ...
- cell1这个字符串如何截取掉前边的cell剩下后边的数字 后边数字长度不固定
cell1这个字符串如何截取掉前边的cell剩下后边的数字 后边数字长度不固定'cell1'.replace(/cell/,'')string.substr(4)string.slice(4)
- C# 之 Excel 导入一列中既有汉字又有数字:数字可以正常导入,汉字导入为空
今天在做一个Excel导入功能,一切开发就绪,数据可以成功导入.导入后检查数据库发现有一列既有汉字又有数字,数字正常导入,汉字为空.但是前面同样既有汉字又有数字的列可以导入成功. 查看excel 源文 ...
随机推荐
- Liunx常用操作(九)-进阶命令
一.查看用户who 1.查看所有用户:who
- RSA 加密,解密,签名,验签
一.RSA加密简介 RSA加密是一种非对称加密.可以在不直接传递密钥的情况下,完成解密.这能够确保信息的安全性,避免了直接传递密钥所造成的被破解的风险. 是由一对密钥来进行加解密的过程,分别称为公钥和 ...
- CSS - 怎么样在不同分辨率的情况下计算根元素需要的font-size的值
一般我们做页面,肯定都会有设计图,移动端页面,一般情况下,UI出图都会定宽为640px,这也是移动端的标准尺寸:但是,我们也不能排除可能有其他特殊的情况可能需要做其他大小的设计图.所以,我们可以先定一 ...
- JDK21更新特性详解
有的时候博客内容会有变动,首发博客是最新的,其他博客地址可能会未同步,认准https://blog.zysicyj.top 首发博客地址 文章更新计划 文章更新计划 | 430: | String T ...
- [转帖]MySQL运维实战(2)MySQL用户和权限管理
https://segmentfault.com/a/1190000044514403 作者:俊达 引言 MySQL数据库系统,拥有强大的控制系统功能,可以为不同用户分配特定的权限,这对于运维来说至关 ...
- [转帖]TiDB 统计数据库占用大小的N种方法
TiDB之路2022-03-06 3896 前言 TiDB 如何统计数据库占用空间大小 四种方法 方法一 TiDB 统计数据库占用大小的第一种方法是监控.通过查看 {cluster-name} - O ...
- [转帖]crash工具分析Kdump下vmcore文件常用命令总结(三)(实例易懂)
一.简介 本文主要介绍使用crash工具对kdump生成的vmcore文件进行分析,解析常见的crash命令,前面已讲述两章关于Kdump的内容,读者感兴趣可以点击下面的链接: 1.Kdump调试机理 ...
- [转帖]Shell脚本中利用expect实现非交互式
https://developer.aliyun.com/article/885723?spm=a2c6h.24874632.expert-profile.295.7c46cfe9h5DxWK 简介: ...
- [转帖]History of Web Browser Engines from 1990 until today
https://eylenburg.github.io/browser_engines.htm Many tried, few remain... Last updated: January 2023 ...
- [转帖] Linux命令拾遗-网络抓包工具
https://www.cnblogs.com/codelogs/p/16060684.html 简介# Linux中有很多抓包工具,如ngrep.tcpdump与tshark等,它们有很多用法与使用 ...