LeetCode 笔记系列11 First Missing Positive [为什么我们需要insight]

题目: 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.

为什么这道题值得纪念呢? 因为它教育我们看问题看本质。

要看出问题本质,首先要深刻理解问题本身是在说啥。。。(越来越像学习某某core的讲话了)

在一个无序的整数数组中,找出第一个没有的正数。什么意思呢?这么想,所有正数是1,2,3,4,5,....(把8倒过来). 找出最小的在这个数组中没有的数。而且人家要O(n),那说明你就没法用排序算法了。但是你肯定想到用hash是不是。一般来说,切题用hash都是没有办法的办法,不过人说了,“uses constant space“,hash都没法用了是不。

我遇到这样的题第一个本能的想法是用bit位移来做。这其实是有些讨巧的hash方法,相当于hash表的长度就只有一个整数大小。首先扫描数组,如果遇到正数i,就把该某个int值的i位置1。最后扫描那个int值,找出第一个0值。也是O(n)有木有。。。

代码是酱紫的。

解法一:

 1 public static int firstMissingPositive(int[] A) {
 2             // Start typing your Java solution below
 3             // DO NOT write main() function
 4            int bits = 0;
 5            for(int i = 0; i < A.length; i++){
 6                if(A[i] > 0){
 7                    bits |= (1 << (A[i] - 1));
 8                }
 9            }
10            int idx = 0;
11            while(bits%2 != 0){
12                bits = (bits >> 1);
13                idx++;
14            }
15            return idx + 1;
16      }
View Code

我觉得也符合条件呀,然后大集合就废了。超时超时。。。。

解法二:

我发现大牛们的有几个共同的特点。1. 比较快速地看问题本质;2. 可能切题很多,比较容易举一反三。

比如这个题,假设数组长度是n。那么第一个missing的正数肯定不会超过n啊混蛋。如果把所有正数都放在正确的位置上,数字1(如果有的话)在A[0], 数字2(如果有的话)在A[1],数字i + 1在A[i],那么我们只要扫描A,遇到第一个A[i]不等于i+1的,就知道这个missing的正数(i+1)了。大家可以用上面的例子仔细想想这个道理。但是怎么在O(n)时间内把数字i + 1(如果有的话)移动到A[i]呢?我估计大牛们肯定早就知道这个算法了。“范围内整数的线性排序”,我之前也在wiki上见过。就是把1-n的整数放置到长度为n的数组中,有序,in-place。

具体方法是,扫描数组A,如果当前的正数A[i]不在其该在的位置,那和A[A[i]-1]交换(这样交换过后A[i]-1的正数就in postion了。继续,直到i位置上的正数是正确的。然后继续下一个交换。

这样总能把所有正数in position。

差距,差距呀。。。

先上代码。

 1 public static int firstMissingPositive2(int[] A){
 2         for(int i = 0; i < A.length; i++){
 3             if(A[i] > 0 && A[i] <= A.length){
 4                 if(A[i] != i + 1 && A[A[i] - 1] != A[i]){
 5                     int tmp = A[A[i] - 1];
 6                     A[A[i] - 1] = A[i];
 7                     A[i] = tmp;
 8                     i--;
 9                 }
10             }
11         }
12         
13         for(int i = 0; i < A.length; i++){
14             if(A[i] != i+1){
15                 return i+1;
16             }
17         }
18         return A.length + 1;
19      }
View Code

这里在swap之前判断了两个条件,因为数组中并不一定包含所有的可以in-postion的正数。

总结:

1)还是题做得不够多;

2)下笔前分析透彻。

 

 

posted on 2013-07-10 10:08  lichen782  阅读(1089)  评论(0编辑  收藏  举报