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

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

题目描述

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

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

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

[要求]

时间复杂度为 O ( n ) O(n) O(n),空间复杂度为 O ( 1 ) O(1) O(1)

输入描述:

第一行为一个整数N。表示数组长度。
接下来一行N个整数表示数组内的数

输出描述:

输出一个整数表示答案

示例1
输入
4
-1 2 3 4
输出
1
示例2
输入
4
1 2 3 4
输出
5
备注:

1 ⩽ N ⩽ 1 0 6 1 \leqslant N \leqslant 10^6 1N106
− 1 0 9 ⩽ a r r i ⩽ 1 0 9 -10^9 \leqslant arr_i \leqslant 10^9 109arri109


法一:
  • 使用两个指针 l、r,l 表示遍历到目前为止,数组已经包含的正整数范围是 [1, l] ,所以开始 l = 0 ;r 表示遍历到目前为止,在后续出现最优状况的情况下,arr 可能包含的正整数范围是 [1, r] ,所以开始时 r = n;
  • 从左到右遍历 arr ,遍历到位置 l ,位置 l 的数为 arr[l];
  • 若 arr[l] == l + 1,在没有遍历到 arr[l] 之前,arr 已经包含的正整数范围是 [1, l] ,此时出现 arr[l] == l + 1,所以 arr 包含的正整数范围可以扩展到 [1, l+1] ,即 l++;
  • 若 arr[l] <= l,因为没有遍历到 arr[l] 之前,arr 在后续最优的情况下可能包含的正整数范围是 [1, l],需要的是 [l+1, r] 范围上的数,此时出现了 arr[l] <= l,说明 [l+1, r] 范围上的数字少了一个,所以 arr 在后续最优的情况下,可能包含的正整数范围缩小了,变为 [1, r-1] ,此时把 arr 最后位置的数(arr[r-1]) 放在位置 l 上,下一步继续检查这个数字,然后 --r ;
  • 若 arr[l] > r,同上;
  • 若 arr[ arr[l]-1 ] == arr[l],此时说明 arr[l] 在 [l+1, r] 范围内,而 arr[l] 应该在 arr[l] - 1 位置上,但是 arr[ arr[l]-1 ] == arr[l] ,说明出现了两个 arr[l] ,同样的,[l+1, r] 范围上的数又少了一个,操作同上;
  • 此时此刻,说明发现了 [l+1, r] 范围上的数,且未重复,将其放在 arr[l] - 1 位置,继续判断 l 位置上新的元素;
  • 最终 l 和 r 位置会碰到一起,此时 arr 已经包含的正整数范围是 [1,l] ,返回 l + 1 即可。
法一代码:
#include <cstdio>
#include <algorithm>

using namespace std;

const int N = 1000001;

int n;
int a[N];

int main( void ) {
    scanf("%d", &n);
    for ( int i = 0; i < n; ++i ) {
        scanf("%d", a + i);
    }
    int l = 0, r = n;
    while ( l < r ) {
        if ( a[l] == l + 1 ) ++l;
        else if ( a[l] <= l || a[l] > r || a[a[l] - 1] == a[l] ) {
            a[l] = a[--r];
        } else swap( a[l], a[a[l]-1] );
    }
    return 0 * printf("%d\n", l + 1);
}
法二:

建立一个大小为 n 的哈希表,把 1 <= arr[i] <= n 的元素标记,然后从 1~n 遍历,若 hash[i] == 0 ,说明 i 是数组中未出现的最小正整数,直接输出即可。

法二代码:
#include <cstdio>

using namespace std;

const int N = 1000001;

int n;
bool a[N];

int main( void ) {
    scanf("%d", &n);
    int val;
    for ( int i = 0; i < n; ++i ) {
        scanf("%d", &val);
        if ( val <= 0 || val > n ) continue;
        a[val] = true;
    }
    for ( int i = 1; i <= n; ++i ) {
        if ( !a[i] ) return 0 * printf("%d\n", i);
    }
    return 0 * printf("%d\n", n + 1);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值