【Leetcode】41. First Missing Positive

题目地址:

https://leetcode.com/problems/first-missing-positive/

给定一个长为 n n n的数组,返回从 1 , 2 , 3 , . . . 1,2,3,... 1,2,3,...中第一个未出现在数组里的数。基本思路是,遍历数组时,如果遍历到的数字 k k k k ∈ { 1 , 2 , . . . , n } k\in\{1,2,...,n\} k{1,2,...,n},就把 k k k给swap到 n u m s [ k − 1 ] nums[k-1] nums[k1],直到无法满足swap条件时,再遍历下一个数字。遍历完成之后,只需返回数组从左到右第一个 i + 1 i+1 i+1使得 n u m s [ i ] = i + 1 nums[i]=i+1 nums[i]=i+1即可。例如对于 ( 3 , 4 , − 1 , 1 ) (3,4,-1,1) (3,4,1,1)进行下列交换: ( -1 , 4 , 3 , 1 ) (\textbf{-1},4,\textbf{3},1) (-1,4,3,1) ( − 1 , 1 , 3 , 4 ) (-1,\textbf{1},3,\textbf{4}) (1,1,3,4) ( 1 , -1 , 3 , 4 ) (\textbf{1},\textbf{-1},3,4) (1,-1,3,4)最后得到的是: ( 1 , − 1 , 3 , 4 ) (1,-1,3,4) (1,1,3,4)可以看出,凡是在 1 ∼ n 1\sim n 1n之间的数都已经归位了,接下来只需要从左向右遍历,返回第一个未出现的正整数就行了。

class Solution {
 public:
  int firstMissingPositive(vector<int>& a) {
    int n = a.size();
    for (int i = 0; i < n; i++) 
      while (1 <= a[i] && a[i] <= n && a[a[i] - 1] != a[i]) 
        swap(a[i], a[a[i] - 1]);
    for (int i = 0; i < n; i++)
      if (a[i] != i + 1) return i + 1;
    return n + 1;
  }
};

时间复杂度 O ( n ) O(n) O(n)

算法正确性证明:
显然,对于 { 1 , 2 , 3 , . . . } \{1,2,3,...\} {1,2,3,...}里第一个不属于数组的数 r r r ∀ k ∈ { 1 , 2 , . . . , r − 1 } \forall k\in \{1,2,...,r-1\} k{1,2,...,r1},在数组遍历完后一定放在了数组的第 k k k个位置,也就是 n u m s [ k − 1 ] nums[k-1] nums[k1]。所以第二个for循环可以把 r r r找出来,算法正确性证明完毕。

算法复杂度证明:
只需证明swap的执行次数不超过 n n n即可。可以理解为,每次进行swap(nums, nums[i] - 1, i)的时候,就对数组的下标 n u m s [ i ] − 1 nums[i] - 1 nums[i]1进行染色。显然同一个位置最多染色一次,并且染色次数不会超过 n n n,所以swap执行次数不超过 n n n

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值