一道面试题Lintcode196-Find the Missing Number
2015-09-18 13:53
363 查看
http://www.lintcode.com/en/problem/find-the-missing-number/#
Example
Given N =
Challenge
Do it in-place with O(1) extra memory and O(n) time.
题意:这是一道面试题目,题意是说给你个数组0-n,让你找出里面唯一缺少的那个数。
思路:我的第一思路是二叉堆,但好像南辕北辙了。可以直接利用快排,少于nlgn的时间就可以找到那个数。利用数值与数组下标的对应关系,数组的数排好序后分两段,左端数值与下标相同,右端则数值比下标大一。不需要排序,只需要借助快排,就可以不断的递归二分这个数组,找出那个奇点。
可以参考两篇类似的博文:
/article/5264452.html
/article/5264569.html
代码:tle
之所以tle是因为原题目给有特殊数据,代码里默认快排是x为第一个数,遇到最坏情况,复杂度n*n。下面把x改为最后一个数,就ac了。
ac 279ms
当然,这只是投机取巧,也会遇到最坏情况。相对好的方法是取中间或者取随机数。下面是取中间的实现例子:214ms
最后,说下最直接简单的办法,以空间换时间,加一个bool数组再哈希就可以了。135ms
经好心博友提醒,最优雅的法子横空出世--异或。两个相同的数异或为0。故而把原数组与0-n异或和就为最后的结果。131ms
看到了官方给的答案---借助桶排序。思路是:从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,以对应第二种情况。详情见代码:
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 =
3and the array
[0, 1, 3], return
2.
Challenge
Do it in-place with O(1) extra memory and O(n) time.
题意:这是一道面试题目,题意是说给你个数组0-n,让你找出里面唯一缺少的那个数。
思路:我的第一思路是二叉堆,但好像南辕北辙了。可以直接利用快排,少于nlgn的时间就可以找到那个数。利用数值与数组下标的对应关系,数组的数排好序后分两段,左端数值与下标相同,右端则数值比下标大一。不需要排序,只需要借助快排,就可以不断的递归二分这个数组,找出那个奇点。
可以参考两篇类似的博文:
/article/5264452.html
/article/5264569.html
代码:tle
class Solution { public: /** * @param nums: a vector of integers * @return: an integer */ int j18(vector<int> &nums,int i,int j){ int x=nums[i]; while(1){ while(i<j&&nums[j]>x) j--; if(i<j) nums[i]=nums[j]; else{ nums[i]=x; return i; } while(i<j&&nums[i]<x) i++; if(i<j) nums[j]=nums[i]; else{ nums[j]=x; return j; } } } int findMissing(vector<int> &nums) { // write your code int i=0,j=nums.size()-1,y; while(y=j18(nums,i,j),1){ if(nums[y]==y) i=y+1; else j=y-1; if(i>j) return i; } } };
之所以tle是因为原题目给有特殊数据,代码里默认快排是x为第一个数,遇到最坏情况,复杂度n*n。下面把x改为最后一个数,就ac了。
ac 279ms
class Solution { public: /** * @param nums: a vector of integers * @return: an integer */ int j18(vector<int> &nums,int i,int j){ int x=nums[j]; while(1){ while(i<j&&nums[i]<x) i++; if(i<j) nums[j]=nums[i]; else{ nums[j]=x; return j; } while(i<j&&nums[j]>x) j--; if(i<j) nums[i]=nums[j]; else{ nums[i]=x; return i; } } } int findMissing(vector<int> &nums) { // write your code int i=0,j=nums.size()-1,y; while(y=j18(nums,i,j),1){ if(nums[y]==y) i=y+1; else j=y-1; if(i>j) return i; } } };
当然,这只是投机取巧,也会遇到最坏情况。相对好的方法是取中间或者取随机数。下面是取中间的实现例子:214ms
class Solution { public: /** * @param nums: a vector of integers * @return: an integer */ int j18(vector<int> &nums,int i,int j){ int x=nums[(i+j)>>1]; nums[(i+j)>>1]=nums[i]; while(1){ while(i<j&&nums[j]>x) j--; if(i<j) nums[i]=nums[j]; else{ nums[i]=x; return i; } while(i<j&&nums[i]<x) i++; if(i<j) nums[j]=nums[i]; else{ nums[j]=x; return j; } } } int findMissing(vector<int> &nums) { // write your code int i=0,j=nums.size()-1,y; while(y=j18(nums,i,j),1){ if(nums[y]==y) i=y+1; else j=y-1; if(i>j) return i; } } };
最后,说下最直接简单的办法,以空间换时间,加一个bool数组再哈希就可以了。135ms
class Solution { public: /** * @param nums: a vector of integers * @return: an integer */ int findMissing(vector<int> &nums) { // write your code int len=nums.size(); bool numb[len+1]; memset(numb,0,sizeof(numb)); for(int i=0;i<len;i++) numb[nums[i]]=true; for(int i=0;i<=len;i++){ if(numb[i]==false) return i; } } };
经好心博友提醒,最优雅的法子横空出世--异或。两个相同的数异或为0。故而把原数组与0-n异或和就为最后的结果。131ms
class Solution { public: /** * @param nums: a vector of integers * @return: an integer */ int findMissing(vector<int> &nums) { // write your code int len=nums.size(),x=0; for(int i=0;i<len;i++) x^=nums[i]; for(int i=1;i<=len;i++) x^=i; return x; } };
看到了官方给的答案---借助桶排序。思路是:从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,以对应第二种情况。详情见代码:
class Solution { public: /** * @param nums: a vector of integers * @return: an integer */ int findMissing(vector<int> &nums) { // write your code int len=nums.size(),x=len; for(int i=0;i<len;i++){ while(nums[i]!=i){ if(nums[i]==len){ x=i; break; }else{ int tmp=nums[nums[i]];//注意这个地方,不能用三个异或来交换值,因为nums[nums[i]]里的nums[i]是变量。 nums[nums[i]]=nums[i]; nums[i]=tmp; } } } return x; } };
相关文章推荐
- 面试题总结-new 和malloc 区别
- 谈女程序员的问题
- 谈一谈我所理解的面试
- 30多年程序员生涯经验总结
- 黑马程序员-Java基础学习第六天总结
- 黑马程序员-Java基础学习第五天总结
- 12款令程序员惊叹的CSS3效果库
- 关于内存面试题引发的思考
- 海格面试题总结
- 黑马程序员__java面向对象__构造函数和继承
- Android面试准备:内存泄露和内存溢出
- 面试官有问题?我看是你有问题吧!
- 黑马程序员——ios开发基础之OC简介
- 面试题 30
- 程序员必须知道的10大基础实用算法及其讲解
- 黑马程序员-Java基础学习第三天总结
- 13 种激励程序员的方法
- 面试题 29
- 通过六个题目彻底掌握String笔试面试题
- 程序员书单_java学习基础编程篇