LeetCode41. 缺失的第一个正数
题目描述
/**
* 给你一个未排序的整数数组 nums ,请你找出其中没有出现的最小的正整数。
* <p>
* 请你实现时间复杂度为 O(n) 并且只使用常数级别额外空间的解决方案。
*
*/
思路分析
- 可以使用Hash结构的快速查找元素特性
- 将数组中所有元素添加到集合中,因为数组元素有len = nums.length个,刚好为 1 ---- > len,然后从1但len遍历,判断集合中是否存在,如果都存在,则最小正整数为 len + 1
- 否则为不存在的那个数
- 源码见下,但是这样的话开辟的新的空间,
- 考虑如何在不开辟新空间的情况下完成此要求???
- 如果不开辟新空间,那么就要合理的利用旧空间,及修改原数组的结构,即修改原数组中的元素
- 先将原数组中的所有 小于等于0的元素全部置为 len + 1 ,因为这些元素不参与最小正整数的查找
- 则在判断的时候添加 < len 条件即可去除这些数
- 然后遍历数组中其他元素,添加 <= len条件后剩下的元素全部在 1 到 len之间,将数组中所在元素拿出来,将其对应的索引位置的元素置为负数,即添加一个标记,那么在处理完之后则很快能找到最小的正整数
- 分析见下
源码及分析
public int firstMissingPositive1(int[] nums) {
int len = nums.length;
//数据校验
if (nums == null || len == 0) {
return 1;
}
//hash结构判断是否存在于集合中
HashSet<Integer> set = new HashSet<>();
//将数组元素添加到集合中
for (int i = 0; i < len; i++) {
set.add(nums[i]);
}
//判断是否存在
for (int i = 1; i <= len; i++) {
if (!set.contains(i)) {
return i;
}
}
return len + 1;
}
满足空间复杂度的算法设计
public int firstMissingPositive(int[] nums) {
int len = nums.length;
//数据校验
if (nums == null || len == 0) {
return 1;
}
//将数组中所有小于等于0的数全部变为 len + 1 ,即将他们全部置为正数
for (int i = 0; i < len; i++) {
if (nums[i] <= 0) {
nums[i] = len + 1;
}
}
//遍历数组中的元素,将小于等于len的元素,将它对应的索引位置的元素全部置为负数,即添加标记
for (int i = 0; i < len; ++i) {
//记录这个元素所在的索引
int num = Math.abs(nums[i]);
if (num <= len) {
//将索引处的元素置为负数
nums[num - 1] = -Math.abs(nums[num - 1]);
}
}
//遍历集合寻找没有添加标记的元素,若都添加标记,则最小正整数为 len + 1
for (int i = 0; i < len; i++) {
if (nums[i] > 0) {
return i + 1;
}
}
return len + 1;
}