一 目录
不折腾的前端,和咸鱼有什么区别
目录 |
---|
一 目录 |
二 前言 |
三 解题及测试 |
四 LeetCode Submit |
五 解题思路 |
二 前言
难度:简单
涉及知识:数组
题目地址:https://leetcode-cn.com/problems/degree-of-an-array/
题目内容:
给定一个非空且只包含非负数的整数数组 nums,
数组的度的定义是指数组里任一元素出现频数的最大值。
你的任务是找到与 nums 拥有相同大小的度的最短连续子数组,返回其长度。
示例 1:
输入: [1, 2, 2, 3, 1]
输出: 2
解释:
输入数组的度是 2,因为元素 1 和 2 的出现频数最大,均为 2.
连续子数组里面拥有相同度的有如下所示:
[1, 2, 2, 3, 1],
[1, 2, 2, 3],
[2, 2, 3, 1],
[1, 2, 2],
[2, 2, 3],
[2, 2]
最短连续子数组[2, 2]的长度为 2,所以返回 2.
示例 2:
输入: [1,2,2,3,1,4,2]
输出: 6
注意:
nums.length 在1到50,000区间范围内。
nums[i] 是一个在0到49,999范围内的整数。
三 解题及测试
小伙伴可以先自己在本地尝试解题,再回来看看 jsliang 的解题思路。
LeetCode 给定函数体:
/**
* @param {number[]} nums
* @return {number}
*/
var findShortestSubArray = function(nums) {
};
根据上面的已知函数,尝试破解本题吧~
确定了自己的答案再看下面代码哈~
index.js
/**
* @name 数组的度
* @param {number[]} nums
* @return {number}
*/
const findShortestSubArray = (nums) => {
const map = new Map();
for (let i = 0; i < nums.length; i++) {
if (map.get(nums[i]) !== undefined) {
map.set(nums[i], map.get(nums[i]) + 1);
} else {
map.set(nums[i], 1);
}
}
let maxNumber = Number.MIN_SAFE_INTEGER;
let maxNumberList = [];
for (let [key, value] of map) {
if (value > maxNumber) {
maxNumber = value;
maxNumberList = [key];
} else if (value === maxNumber) {
maxNumberList.push(key);
}
}
let result = Number.MAX_SAFE_INTEGER;
for (let i = 0; i < maxNumberList.length; i++) {
result = Math.min(result, nums.lastIndexOf(maxNumberList[i]) - nums.indexOf(maxNumberList[i]) + 1);
}
return result;
};
console.log(findShortestSubArray([1, 2, 2, 3, 1])); // 2
console.log(findShortestSubArray([1, 2, 2, 3, 1, 4, 2])); // 6
node index.js
返回:
2
6
四 LeetCode Submit
Accepted
* 89/89 cases passed (136 ms)
* Your runtime beats 44.68 % of javascript submissions
* Your memory usage beats 72.73 % of javascript submissions (39.5 MB)
五 解题思路
忍不住想翻答案,最终敌不过自己的好强心。
第一次题解如下所示:
哈希表
const findShortestSubArray = (nums) => {
const map = new Map();
for (let i = 0; i < nums.length; i++) {
if (map.get(nums[i]) !== undefined) {
map.set(nums[i], map.get(nums[i]) + 1);
} else {
map.set(nums[i], 1);
}
}
let maxNumber = Number.MIN_SAFE_INTEGER;
let maxNumberList = [];
for (let [key, value] of map) {
if (value > maxNumber) {
maxNumber = value;
maxNumberList = [key];
} else if (value === maxNumber) {
maxNumberList.push(key);
}
}
let result = Number.MAX_SAFE_INTEGER;
for (let i = 0; i < maxNumberList.length; i++) {
result = Math.min(result, nums.lastIndexOf(maxNumberList[i]) - nums.indexOf(maxNumberList[i]) + 1);
}
return result;
};
题解思路为:
设置
map
存储哈希。第一个
for
遍历,将所有的值及其出现的次数,统计到map
中。设置最大值
maxNumber
及最大值都有哪些值maxNumberList
。第二个
for
遍历,将maxNumber
和maxNumberList
填充上。设置结果为
result
。第三个
for
遍历,将maxNumberList
过一遍,在nums
中查找maxNumberList
中每个元素的indexOf
和lastIndexOf
,通过lastIndexOf - indexOf + 1
的计算,可以得到最短路线。返回结果为
result
。
Submit 提交如下:
Accepted
* 89/89 cases passed (136 ms)
* Your runtime beats 44.68 % of javascript submissions
* Your memory usage beats 72.73 % of javascript submissions (39.5 MB)
刚才讲解思路的时候,突然想起,我好像可以将两个 for
结合成一个,方法如下:
哈希表优化
const findShortestSubArray = (nums) => {
let newNums = [...new Set(nums)];
let timeMax = Number.MIN_SAFE_INTEGER;
let result = Number.MAX_SAFE_INTEGER;
for (let i = 0; i < newNums.length; i++) {
const length = nums.filter(item => item === newNums[i]).length;
if (length > timeMax) {
result = nums.lastIndexOf(newNums[i]) - nums.indexOf(newNums[i]) + 1;
timeMax = length;
} else if (length === timeMax) {
result = Math.min(result, nums.lastIndexOf(newNums[i]) - nums.indexOf(newNums[i]) + 1);
timeMax = length;
}
}
return result;
};
思路如下:
设置
newNums
来简化我们需要遍历的nums
长度。设置
timeMax
记录出现次数最多的值。设置
result
记录需要返回的长度。遍历
newNums
,查找每一个元素在原nums
中出现的次数。判断这个长度是大于
timeMax
还是等于timeMax
。如果
length > timeMax
,那么我们重新设置result = lastIndexOf - indexOf + 1
;如果
length = timeMax
,那么我们取原result
和目前lastIndexOf - indexOf + 1
中的最小值。返回结果。
Submit 提交:
Accepted
* 89/89 cases passed (468 ms)
* Your runtime beats 5.67 % of javascript submissions
* Your memory usage beats 36.36 % of javascript submissions (42.2 MB)
代码是 精简 了,但是因为它使用了双重循环嵌套,所以比起第一次来还更加不如。
如果你有更好的思路或者看法,欢迎评论留言或者私聊 jsliang~
不折腾的前端,和咸鱼有什么区别!
jsliang 会每天更新一道 LeetCode 题解,从而帮助小伙伴们夯实原生 JS 基础,了解与学习算法与数据结构。
浪子神剑 会每天更新面试题,以面试题为驱动来带动大家学习,坚持每天学习与思考,每天进步一点!
扫描上方二维码,关注 jsliang 的公众号(左)和 浪子神剑 的公众号(右),让我们一起折腾!
jsliang 的文档库 由 梁峻荣 采用 知识共享 署名-非商业性使用-相同方式共享 4.0 国际 许可协议进行许可。
基于https://github.com/LiangJunrong/document-library上的作品创作。
本许可协议授权之外的使用权限可以从 https://creativecommons.org/licenses/by-nc-sa/2.5/cn/ 处获得。