[LeetCode] First Missing Positive

Given an unsorted integer array, find the first missing positive integer.
For example, Given [1,2,0] return 3, and [3,4,-1,1] return 2.
Your algorithm should run in O(n) time and uses constant space.

本质上是桶排序,如果不是要求O(1)的空间,可以之间开一个O(n)的数组,全部标记为0,然后A中出现过的标记为1,即可解决此问题。

但是此题要求O(1)的空间,我们用A[i]保存i+1,这样最好做一次判断A[i] 不是i+1的内容即可达到目的。

虽然不能再另外开辟非常数级的额外空间,但是可以在输入数组上就地进行swap操作。

 1 class Solution {
 2  public:
 3   int firstMissingPositive(int A[], int n) {
 4     for(int i = 0 ; i < n; ) {
 5       if((A[i] > 0) && (A[i] <= n) && (A[A[i]-1] != A[i])) {
 6         int t = A[A[i]-1];
 7         A[A[i]-1] = A[i];
 8         A[i] = t;
 9       } else i++;
10     }
11     for(int i = 0 ; i < n; i++) {
12       if(A[i] != i+1) return i+1;
13     }
14     return n+1;
15   }
16 };

下图以题目中给出的第二个例子为例,讲解操作过程。

首先思路上,其次临界条件,这题和下面题异曲同工:

n个元素的数组,里面的数都是0~n-1范围内的,求数组中重复的某一个元素,没有返回-1, 要求时间性能O(n) 空间性能O(1)。

 1 bool IsDuplicateNumber(int *array, int n)
 2 {    
 3     if(array==NULL) return false;    
 4     int i,temp;
 5     for(i=0;i<n;i++)        
 6     {    
 7         while(array[i]!=i)            
 8         {        
 9             if(array[array[i]]==array[i]) 
10                 return true;    
11             temp=array[array[i]];    
12             array[array[i]]=array[i];        
13             array[i]=temp;            
14         }        
15     }    
16     return false;    
17 }

把每个数放到自己对应序号的位置上,如果其他位置上有和自己对应序号相同的数,那么即为有重复的数值。

当没有重复数值出现时,可以看做一种特殊的排序。

看到“里面的数都属于范围[0,n-1]”会不会条件反射想到计数排序? 可惜题目要求O(1)空间,而且仔细看题就知道与计数排序八竿子打不着。不过计数排序里面蕴含的思想我们还是可以使用的。

    回忆一下计数排序的算法,如果待排序的值大小范围在[0,n-1]之内,我们完全可以构造一个数组B[n],将待排序数组中,值为x(0<=x<=n-1)的元素放到B[x]中去,这里暂时先不说重复的情况。说白了就是如果有元素的值范围都在一个固定区间内的情况,那么我们完全可以把元素的值与数组下标映射起来。那么这道题也一样。

    下面给出一位网友的做法,就原数组的值和下标进行交换,然后新值是个标记。o(n)内可以找到相同标记就返回。只要1个中间变量。当然这个做法可不一定正确,也不一定是最优的。大家仁者见仁智者见智哈。

原文地址:https://www.cnblogs.com/diegodu/p/3788280.html