持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第19天,点击查看活动详情
前言
今天来一道数组相关的题目,题目难度为困难等级,看到这个困难搞的我都多想了,导致我自己想的太复杂,搞了好久,下面先来看一下题目描述吧。
题目描述
给你一个未排序的整数数组 nums ,请你找出其中没有出现的最小的正整数。
请你实现时间复杂度为 O(n) 并且只使用常数级别额外空间的解决方案。
示例 1:
输入:nums = [1,2,0]
输出:3
示例 2:
输入:nums = [3,4,-1,1]
输出:2
示例 3:
输入:nums = [7,8,9,11,12]
输出:1
解题思路
这题有个坑,题目中说给了一个未排序的数组,这里有可能会让你想到先来个排序,其实并不用,这题的核心就两点。
- 利用哈希表把数组中的各项都做一下标记
- 直接循环[1,n+1],然后判断当前项在不在哈希表中就可以了 代码如下:
/**
* @param {number[]} nums
* @return {number}
*/
var firstMissingPositive = function (nums) {
var map = new Map()
for (let i = 0; i < nums.length; i++) {
if (!map.get(nums[i])) {
map.set(nums[i], 1)
}
}
for (let j = 1; j <= nums.length+1; j++) {
if (!map.get(j)) {
return j
}
}
};
运行结果如下:
上述方法可以成功提交通过,其实可以完全不用哈希表,直接遍历[1,n+1],然后用array.indexOf(j)来判断是不是等于-1就可以了,但是这样会超过时间限制。如下:
/**
* @param {number[]} nums
* @return {number}
*/
var firstMissingPositive = function (nums) {
// var map = new Map()
// for (let i = 0; i < nums.length; i++) {
// if (!map.get(nums[i])) {
// map.set(nums[i], 1)
// }
// }
for (let j = 1; j <= nums.length+1; j++) {
if (nums.indexOf(j)===-1) {
return j
}
}
};
优化
这一题中提到的达到空间的O(1)还是很有意思的,要实现这个可以借助原数组来实现一种类似哈希表的东西。具体步骤如下:
- 首先把数组中小于0的项给改变了,可以改变成任意大约N的数
- 然后遍历这个数组,拿当前项和数组的长度进行对比,如果小于长度的话就把num-1标记为负
- 遍历标记后的数据,第一个大于0的项的下标加1就是结果 代码如下:
/**
* @param {number[]} nums
* @return {number}
*/
var firstMissingPositive = function (nums) {
for (let i = 0; i < nums.length; ++i) {
if (nums[i] <= 0) {
nums[i] = nums.length + 1;
}
}
for (let i = 0; i < nums.length; ++i) {
let num = Math.abs(nums[i]);
if (num <= nums.length) {
nums[num - 1] = -Math.abs(nums[num - 1]);//这里有点难理解,打标记的其实是下标位置的数,也就是打标记的下标
}
}
for (let i = 0; i < nums.length; ++i) {
if (nums[i] > 0) {
return i + 1;
}
}
return nums.length + 1;
};
结果如下: