zoukankan      html  css  js  c++  java
  • 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)下笔前分析透彻。

  • 相关阅读:
    利用kettle中的JS来完成ETL数据校验
    spring cloud学习地址
    centos7 卸载 gitlab
    为什么WEB-INF外的jsp无法根据cookie享受国际化
    改变maven父子项目视图为树状
    maven profiles、filters、resources学习笔记 及 常用 plugin demo
    Tomcat 签名认证配置简例
    CentOS 开机启动
    Tomcat 关闭时报错
    比较全的log4j示例
  • 原文地址:https://www.cnblogs.com/lichen782/p/leetcode_First_Missing_Positive.html
Copyright © 2011-2022 走看看