数组

1.缺失的第一个正数  

要求时间复杂度应为O(n),空间复杂度为常数。

方法一:哈希表(空间复杂度不符合要求)
按照刚才我们读例子的思路,其实我们只需从最小的正整数 11 开始,依次判断 22、 33 、44 直到数组的长度 N 是否在数组中。

如果当前考虑的数不在这个数组中,我们就找到了这个缺失的最小正整数。

由于我们需要依次判断某一个正整数是否在这个数组里,我们可以先把这个数组中所有的元素放进哈希表。接下来再遍历的时候,就可以以 O(1)O(1) 的时间复杂度判断某个正整数是否在这个数组。

由于题目要求我们只能使用常数级别的空间,而哈希表的大小与数组的长度是线性相关的,因此空间复杂度不符合题目要求。

参考代码 1:

Java
import java.util.HashSet;
import java.util.Set;

public class Solution {

public int firstMissingPositive(int[] nums) {
int len = nums.length;

Set<Integer> hashSet = new HashSet<>();
for (int num : nums) {
hashSet.add(num);
}

for (int i = 1; i <= len ; i++) {
if (!hashSet.contains(i)){
return i;
}
}

return len + 1;
}
}

复杂度分析:

时间复杂度:O(N),这里 N 表示数组的长度。第 1 次遍历了数组,第 2 次遍历了区间 [1, len] 里的元素。
空间复杂度:O(N),把 N个数存在哈希表里面,使用了 N 个空间。

方法二:二分查找(时间复杂度不符合要求)
根据刚才的分析,这个问题其实就是要我们查找一个元素,而查找一个元素,如果是在有序数组中查找,会快一些;

因此我们可以将数组先排序,再使用二分查找法从最小的正整数 11 开始查找,找不到就返回这个正整数;

这个思路需要先对数组排序,而排序使用的时间复杂度是 O(N \log N)O(NlogN),是不符合这个问题的时间复杂度要求。

参考代码 2:

Java
import java.util.Arrays;

public class Solution {

public int firstMissingPositive(int[] nums) {
int len = nums.length;
Arrays.sort(nums);

for (int i = 1; i <= len; i++) {
int res = binarySearch(nums, i);
if (res == -1) {
return i;
}
}
return len + 1;
}

private int binarySearch(int[] nums, int target) {
int left = 0;
int right = nums.length - 1;
while (left <= right) {
int mid = (left + right) >>> 1;
if (nums[mid] == target) {
return mid;
} else if (nums[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return -1;
}
}

复杂度分析:

时间复杂度:O(N \log N),这里 NN 表示数组的长度。时间复杂度主要消耗在排序上,排序使用 O(N\log N)O(NlogN)。二分查找使用 O(\log N)O(logN);
空间复杂度:O(1)。
方法三:将数组视为哈希表
由于题目要求我们“只能使用常数级别的空间”,而要找的数一定在 [1, N + 1] 左闭右闭(这里 N 是数组的长度)这个区间里。因此,我们可以就把原始的数组当做哈希表来使用。事实上,哈希表其实本身也是一个数组;
我们要找的数就在 [1, N + 1] 里,最后 N + 1 这个元素我们不用找。因为在前面的 N 个元素都找不到的情况下,我们才返回 N + 1;
那么,我们可以采取这样的思路:就把 11 这个数放到下标为 00 的位置, 22 这个数放到下标为 11 的位置,按照这种思路整理一遍数组。然后我们再遍历一次数组,第 11 个遇到的它的值不等于下标的那个数,就是我们要找的缺失的第一个正数。
这个思想就相当于我们自己编写哈希函数,这个哈希函数的规则特别简单,那就是数值为 i 的数映射到下标为 i - 1 的位置。

using namespace std;

class Solution {
public:
    int firstMissingPositive(vector<int> &nums) {
        for (int i = 0; i < nums.size(); i++) {
            while (nums[i] != i + 1) {
                if (nums[i] <= 0 || nums[i] > nums.size() || nums[i] == nums[nums[i] - 1])
                    break;
                // 将nums[i] 放置到对应位置上[1,2,3...]
                int idx = nums[i] - 1;
                nums[i] = nums[idx];
                nums[idx] = idx + 1;
            }
        }
        for (int i = 0; i < nums.size(); i++) {
            if (nums[i] != (i + 1)) {
                return (i + 1);
            }
        }
        return (nums.size() + 1);
    }

 

posted @ 2020-04-29 23:02  刘通1997  阅读(191)  评论(0编辑  收藏  举报