zoukankan      html  css  js  c++  java
  • 一道面试题Lintcode196-Find the Missing Number

    http://www.lintcode.com/en/problem/find-the-missing-number/#

    Find the Missing Number

    Given an array contains N numbers of 0 .. N, find which number doesn't exist in the array.

     
    Example

    Given N = 3 and the array [0, 1, 3], return 2.

    Challenge

    Do it in-place with O(1) extra memory and O(n) time.

    题意:这是一道面试题目,题意是说给你个数组0-n,让你找出里面唯一缺少的那个数。

    思路:我的第一思路是二叉堆,但好像南辕北辙了。可以直接利用快排,少于nlgn的时间就可以找到那个数。利用数值与数组下标的对应关系,数组的数排好序后分两段,左端数值与下标相同,右端则数值比下标大一。不需要排序,只需要借助快排,就可以不断的递归二分这个数组,找出那个奇点。

    可以参考两篇类似的博文:

    http://www.cnblogs.com/jiu0821/p/4138558.html

    http://www.cnblogs.com/jiu0821/p/4505480.html

    代码:tle

     1 class Solution {
     2 public:
     3     /**    
     4      * @param nums: a vector of integers
     5      * @return: an integer
     6      */
     7     int j18(vector<int> &nums,int i,int j){
     8         int x=nums[i];
     9         while(1){
    10             while(i<j&&nums[j]>x)  j--;
    11             if(i<j) nums[i]=nums[j];
    12             else{
    13                 nums[i]=x;
    14                 return i;
    15             }
    16             while(i<j&&nums[i]<x)  i++;
    17             if(i<j) nums[j]=nums[i];
    18             else{
    19                 nums[j]=x;
    20                 return j;
    21             }
    22         }
    23     }
    24     int findMissing(vector<int> &nums) {
    25         // write your code 
    26         int i=0,j=nums.size()-1,y;
    27         while(y=j18(nums,i,j),1){
    28             if(nums[y]==y) i=y+1;
    29             else j=y-1;
    30             if(i>j) return i;
    31         }
    32     }
    33 };

    之所以tle是因为原题目给有特殊数据,代码里默认快排是x为第一个数,遇到最坏情况,复杂度n*n。下面把x改为最后一个数,就ac了。

    ac 279ms

     1 class Solution {
     2 public:
     3     /**    
     4      * @param nums: a vector of integers
     5      * @return: an integer
     6      */
     7     int j18(vector<int> &nums,int i,int j){
     8         int x=nums[j];
     9         while(1){
    10             while(i<j&&nums[i]<x)  i++;
    11             if(i<j) nums[j]=nums[i];
    12             else{
    13                 nums[j]=x;
    14                 return j;
    15             }
    16             while(i<j&&nums[j]>x)  j--;
    17             if(i<j) nums[i]=nums[j];
    18             else{
    19                 nums[i]=x;
    20                 return i;
    21             }
    22         }
    23     }
    24     int findMissing(vector<int> &nums) {
    25         // write your code 
    26         int i=0,j=nums.size()-1,y;
    27         while(y=j18(nums,i,j),1){
    28             if(nums[y]==y) i=y+1;
    29             else j=y-1;
    30             if(i>j) return i;
    31         }
    32     }
    33 };

    当然,这只是投机取巧,也会遇到最坏情况。相对好的方法是取中间或者取随机数。下面是取中间的实现例子:214ms

     1 class Solution {
     2 public:
     3     /**    
     4      * @param nums: a vector of integers
     5      * @return: an integer
     6      */
     7     int j18(vector<int> &nums,int i,int j){
     8         int x=nums[(i+j)>>1];
     9         nums[(i+j)>>1]=nums[i];
    10         while(1){
    11             while(i<j&&nums[j]>x)  j--;
    12             if(i<j) nums[i]=nums[j];
    13             else{
    14                 nums[i]=x;
    15                 return i;
    16             }
    17             while(i<j&&nums[i]<x)  i++;
    18             if(i<j) nums[j]=nums[i];
    19             else{
    20                 nums[j]=x;
    21                 return j;
    22             }
    23         }
    24     }
    25     int findMissing(vector<int> &nums) {
    26         // write your code 
    27         int i=0,j=nums.size()-1,y;
    28         while(y=j18(nums,i,j),1){
    29             if(nums[y]==y) i=y+1;
    30             else j=y-1;
    31             if(i>j) return i;
    32         }
    33     }
    34 };

    最后,说下最直接简单的办法,以空间换时间,加一个bool数组再哈希就可以了。135ms

     1 class Solution {
     2 public:
     3     /**    
     4      * @param nums: a vector of integers
     5      * @return: an integer
     6      */
     7     int findMissing(vector<int> &nums) {
     8         // write your code 
     9         int len=nums.size();
    10         bool numb[len+1];
    11         memset(numb,0,sizeof(numb));
    12         for(int i=0;i<len;i++)  numb[nums[i]]=true;
    13         for(int i=0;i<=len;i++){
    14             if(numb[i]==false)
    15                 return i;
    16         }
    17     }
    18 };

    经好心博友提醒,最优雅的法子横空出世--异或。两个相同的数异或为0。故而把原数组与0-n异或和就为最后的结果。131ms

     1 class Solution {
     2 public:
     3     /**    
     4      * @param nums: a vector of integers
     5      * @return: an integer
     6      */
     7     int findMissing(vector<int> &nums) {
     8         // write your code 
     9         int len=nums.size(),x=0;
    10         for(int i=0;i<len;i++)  x^=nums[i];
    11         for(int i=1;i<=len;i++) x^=i;
    12         return x;
    13     }
    14 };

    看到了官方给的答案---借助桶排序。思路是:从0开始遍历到n-1,每次当a[i]!=i的时候,将a[i]与a[a[i]]交换,大于边界的话,就丢掉,直到无法交换位置。那个特殊值有两种情况,一种是在0~n-1之间,那么经过a[i]与a[a[i]]交换,最后以特殊值为下标的位置上一定为n;另一种是特殊值为n,那么a[i]与a[a[i]]交换对于0~n-1都满足。故而只要跟踪边界值n即可,跟踪值x应初始化为n,以对应第二种情况。详情见代码:

     1 class Solution {
     2 public:
     3     /**    
     4      * @param nums: a vector of integers
     5      * @return: an integer
     6      */
     7     int findMissing(vector<int> &nums) {
     8         // write your code 
     9         int len=nums.size(),x=len;
    10         for(int i=0;i<len;i++){
    11             while(nums[i]!=i){
    12                 if(nums[i]==len){
    13                     x=i;
    14                     break;
    15                 }else{
    16                     int tmp=nums[nums[i]];//注意这个地方,不能用三个异或来交换值,因为nums[nums[i]]里的nums[i]是变量。
    17                     nums[nums[i]]=nums[i];
    18                     nums[i]=tmp;
    19                 }
    20             }
    21         }
    22         return x;
    23     }
    24 };
  • 相关阅读:
    前端攻城狮学习笔记九:让你彻底弄清offset
    jquery在线手册
    阻止元素的默认行为
    JS三元运算符
    坐标系与基本图元(1) ~转载天行健 君子当自强而不息
    坐标系与基本图元~转载天行健 君子当自强而不息
    VS常见错误
    ZigZag Conversion
    指针转换(数组退化为指针的三种情况)
    POJ 1985
  • 原文地址:https://www.cnblogs.com/jiu0821/p/4677204.html
Copyright © 2011-2022 走看看