未排序数组,O(N)时间,常数空间,这道题让我非常清晰的感觉到算法的魅力。
先想一下如果允许用额外空间的话,我们会怎么做,对,我们会建立一个hash表,然后从头到尾的扫描数组,等等,怎么映射呢?有n个数,要找第一个消失的正正整数,那么这个消失的正整数的取值范围是什么呢?[1, n+1],之所以包含n+1是因为如果这n数正好是连续的前n个自然数。那我们就知道了,开一个长为n的哈希表,如果当前扫到得数是[1,n]之间的话,就放到数值减1的位置上,如果不是的话就跳过,然后从头扫一遍这个哈希表,第一个没被填上的位置加1的那个数,就是第一个消失的数。
难就难在常数空间上,那题目没有指明不能修改原来的数组,我们能不能就地做一个hash呢?这个要保证个条件,原来位置上的数据不能轻易覆盖,因为如果像开hash表那样直接在对应位置上填数据的话,要么覆盖,要么置换,覆盖会出错,置换会提高整个算法的复杂度。聪明的你可能已经想到了,我们其实不需要在对应的位置上填上那个数,只要保证能区分出一个数在不在他对应的位置上,因此只要正负就可以了。
原来的负数怎么处理?负数肯定不符合要求,只要让他们变成正的,又不会影响我们的结果就好,统一变成n+2是不错的选择。现在,数组中的所有数据都是正的了,如果遇到一个大于等于n+1的数,可以直接略过,他们要么是负数变来的,要么一开始就太大,不是我们考虑的范围。如果遇到一个小于n+1的数据,我们可以知道他应该在的位置(A[i]-1),只要把这个位置标记为负的,就可以知道这个数呆在了它应该的位置上了。发现我们并没有改变原来那个位置上数的数值,它可以继续发挥作用。只不过每次判断的时候要加个abs而已。
class Solution { public: int firstMissingPositive(int A[], int n) { for(int i=0;i<n;i++){ if(A[i]<=0) A[i] = n+2; } for(int i=0;i<n;i++){ if(abs(A[i])<n+1){ int cur = abs(A[i])-1; A[cur] = -abs(A[cur]); } } for(int i=0;i<n;i++){ if(A[i]>0) return i+1; } return n+1; } };
leetcode第一刷_ First Missing Positive,布布扣,bubuko.com
leetcode第一刷_ First Missing Positive
原文地址:http://blog.csdn.net/u012792219/article/details/25742657