数组中未出现的最小正整数

题目:

给定一个无序整型数组arr,找到数组中未出现的最小正整数。

要求时间复杂度为O(N)空间复杂度为O(1)。

例如:

arr=[-1,2,3,4]。返回1。

arr=[1,2,3,4]。返回5。

找到自然数从1-n中,第一个没有出现在给定数组中的

题解一(空间复杂度O(n)):

我们知道数组的长度为n,最后的结果一定在1-n+1之间。我们创建一个长度为n的数组pos,元素初始化为0,之后遍历给定的数组,数组如果有数字i出现,就置pos[i-1]=1。最后遍历一遍pos,发现有pos[i]=0的话,那么最后结果就为i+1。如果在遍历过程中没有返回结果,那么返回n+1。

举个例子有数组arr = [-1, 2, 3, 4],生成的pos为[0,1,1,1]。遍历发现pos[0]=0,那么返回0+1

int minNumberdisappered(vector<int> &arr) {
    int n = arr.size();
    vector<int> pos(n, 0);
    for (int i = 0; i < n; i++) {
        if (arr[i] > 0) {
            pos[arr[i] - 1] = 1;
        }
    }
    for (int i = 0; i < n; i++) {
        if (pos[i] == 0) {
            return i + 1;
        }
    }
    return n + 1;
}

时间复杂度:,我们对两个数组分别遍历了一遍,数组长度均为n。

空间复杂度:,我们创建了长度为n的pos数组。

题解二:缩减空间复杂度

题解一开辟了新的pos数组存储了出现过的数组,如果我们直接在原数组上修改位置,就不用开辟新的数组了。

值为i的数应该存放在arr[i-1]的位置,如果我们尽可能的把所有数放到指定的位置,最后剩下的数就是我们要求的结果。

我们用l表示在1-l的正整数有合适的位置,初始化为0,用r表示右边界,在这个边界的右边都是没有正确位置的数。r的初值为N,所有的数都有位置(不一定是正确的位置)。

当[l+1-r]之间的数,如果其数据不合法,指超越了l+1-r这个范围,我们直接令该数据等于arr[r-1],同时r左移一位如果其数据合法,但其所在位置不对,那么就需要交换到正确的位置arr[l]应该在arr[l]-1处,所有将arr[arr[l]-1]与arr[l]交换即可。

举个例子:如数组arr[-1,2,3,4]

图片说明

图片说明

代码实现如下:

int minNumberdisappered(vector<int>&arr)
{
    int l = 0;
    int r = arr.size();
    while(l < r)
    {
        //元素arr[l]在位置l=arr[l]-1处
        if(arr[l] == l + 1){
            l++;
        }
        else if(arr[l] > r || arr[l] <= l || arr[arr[l] - 1] == arr[l])//不合法的数据
        {
            arr[l] = arr[--r];
        }
        //arr[l]处的数合法但是没有在理想的位置上
        else
        {
            swap(arr[l], arr[arr[l] - 1]);
        }
    }
    return l + 1;
}

时间复杂度:,对数组进行了一遍遍历求和

空间复杂度:,没有额外申请数组。

题解三(可ac但并不完全正确):

数组中只有一个数不符合要求。如果我们把所有符合要求的数(1到n之间的数)相加和为total,与相减,若差值为0,则返回n+1,不为0则返回差值。

这种代码在nc上是ac的,nc测试用例不足。

如当所有的数都在1-n之间,如[1,2,2,3,5],,total值为13,,差值为2,但要求的结果为4.

int minNumberdisappered(vector<int> &arr) {
      int n = arr.size();
    int total = 0;
    int sum = n*(n+1)/2;
    int c = total-sum;
    for(int i=0;i<n;i++){
        if(arr[i]<=0||arr[i]>n){
            continue;
        }
        else{
            //将1-n之间的数相加
            total+=arr[i];
        }
    }
    return total-sum==0?n+1:sum-total;
}

时间复杂度:,对数组进行了一遍遍历求和

空间复杂度:,没有额外申请数组。