据传说是MS/Google等等IT名企业的面试题:

有一组数字,从1到n,中减少了一个数,顺序也被打乱,放在一个n-1的数组里

请找出丢失的数字,最好能有程序,最好算法比较快

BTW1: 有很多种方法的哦,据说O(n)的方法就不止一种

BTW2: 扩展问题,如果丢失了2个数字呢?

BTW3: 一定要小心不要溢出,嗯,面试者有时候不会提醒你的

BTW4: 最好不要多申请n多空间

Update 一个很相近的题目:1-1000放在含有1001个元素的数组中,只有唯一的一个元素值重复,其它均只出现一次。每个数组元素只能访问一次,设计一个算法,将它找出来;不用辅助存储空间,能否设计一个算法实现?

题目 :

  1. 给你n个数,其中有且仅有一个数出现了奇数次,其余的数都出现了偶数次。用线性时间常数空间找出出现了奇数次的那一个数。
  2. 给你n个数,其中有且仅有两个数出现了奇数次,其余的数都出现了偶数次。用线性时间常数空间找出出现了奇数次的那两个数。

现在这里给出一些解答:

第一题: 看到题目的第一反应就是把这个n-1个数字加起来,然后和1+2+3..+n的和进行比较,那个差值就是迷失的数字。但是这个方法正是BTW3里面提到的 不要溢出:)所以有一定的风险,还是不采用,还有人说用一个个+-来判断,可以是可以但是代码写起来也比较难看(个人感觉),还是异或操作符来的最合适一 些。 我们知道1^1=0;2^2=0;n^n=0;k^0=k;所以如果我们把这n-1个数字异或起来,再来异或一下1,2,..n。那么最终的答案肯定是迷 失数字k^(1^1)^(2^2)...^(n^n)。也就是K了。我们很容易地写下来了函数:

 // in case find one missing number, here size is 1 less than the range n
int find_missing_number1 (int a[], int size)
{
int number=;
for (int i=;i<size;i++)
number ^= ((i+)^a[i]);
number ^= (size+);
return number;
}

第二个问题来的更复杂一些,如果有两个数字迷失怎么办?还是方法一的方法,但是需要衍生一下。假定我们迷失的数字是S1,S2那么我们全部异或之后 得到的就是S1^S2只有的值。分析一下就可以知道,S1!=S2,也就是说S1^S2!=0; 这样也就是说S1^S2的这个值有二进制位有一位是1,那么我们就可以把这些所有的数字分成2组,一组这个二进制位是1,另一个这个二进制位是0的来重新 做异或。这样就可以吧其中一个S1求出来了,那再S1^(S1^S2)一下,S2也就得到了。类似地,我们写下了如下的代码:

 // in case find two missing numbers, here size is 2 less than the range n
void find_missing_number2 (int a[], int size, int& miss1, int& miss2)
{
miss1 = ;
miss2 = ;
int number=;
for (int i=;i<size;i++)
number ^= ((i+)^a[i]);
number ^= (size+);
number ^= (size+); // now number will be miss1^miss2
// find the binary 1 in number
int k = number - (number&(number-));
for (int i=;i<size;i++)
{
if ( (i+)&k )
miss1 ^= (i+);
if ( a[i]&k )
miss1 ^= a[i];
}
if ( (size+) & k )
miss1 ^= size+;
if ( (size+) & k )
miss1 ^= size+;
miss2 = number ^ miss1;
}

还找了个test case 测试了一把:看起来两个函数运行的结论是正确的。

 int _tmain(int argc, _TCHAR* argv[])
{
int a[] = { ,,,,,,,, };
int b[] = { ,,,,,,,,, };
int s1,s2;
int k = find_missing_number1(a,sizeof(a)/sizeof(a[]));
find_missing_number2(b,sizeof(b)/sizeof(b[]),s1,s2);
std::cout<<"missing number 1 is "<<k<<std::endl;
std::cout<<"missing number 2 is "<<s1 << " and "<<s2<<std::endl;
system("pause");
return ;
}

后面的问题,Update确实如上所说的,非常类似,把这些个数字和1-1000异或就得到了答案了。奇数偶数的其实问题的第一二小题分别和迷失一个数字和两个数字对应,想法完全一致,这里不做展开了。

--------------------------------

问题1:

1-N的自然数中,少了一个,找出这个数

O(n)空间的比较简单,下面给出几个个只需要1,2个额外变量的算法

(1)求和-容易溢出

S1=1+2+...+N=(N+1)N/2

然后遍历数列每次从S1中减去当前的数字

最后剩下的数字就是所求

为了防止溢出我们可以每次在S1大于一定的数字后,就去减,然后继续求和,再大于就继续减,以此类推。

(2)异或

Y1=1^2^3...^N

然后遍历数列每次异或当前的数字

最后剩下的就是要求的数字

实际上平时我们用的比较多的互逆运算有  加/减   乘/除  对数/幂数

往往忽略了异或也是有一定的互逆性的

(3)O(N)时间的移动-排序

将a[i]移动到a[a[i]],使得数组有序

然后找出空着的位置

(4)O(NlogN)时间的移动-排序

用快排的思想,在1-N中选取游标X对数组快排一次,如果X被放在a[X-1]的位置上那么,要找的数字在X-N之间

否则X被放在a[X-2]的位置上 要找的数字在1-X-1之间   递归求解,直到找的要找的数字。


问题2:

1-N个自然数,少了两个,找出这两个数

(1)求和-容易溢出

S1=1+2+...+N=(N+1)N/2

S2=1^2+2^2+...+N^2=(N+1)(2N+1)N/6    (这里^是表示上标,即平方)

...

对于少了K个数的情况,如果K很少,我们可以找出K个和上面类似的函数,计算总体值,然后用解K元一次方程得到结果

但要注意函数的选择

(2)异或

按照上面同样的方法,求出最后的值P等于两个数的异或

确定P从低位到高位的第一个1是第i位

现在用快排的思想,将数列分成两个区间A和B

其中A中第i位是0,B中的第i位是1

然后调用问题1中的方法来分别求解A和B

(3)O(N)时间移动-排序

跟上面一样,实际上这种方法对于少了K个数的情况都能适用。

(4)O(NlogN)时间移动-排序

跟上面的方法一样

如果X被放在a[X-1]位置上,要找的两个数字在X-N之间

如果X被放在a[X-2]位置上,要找的数字一个在1-X-1间,一个在X-N之间

如果X被放在a[X-3]位置上,要找的数字都在1-X-1间

对于少了K个数字的情况,这种方法也可以做,但实现起来就比较复杂了


问题3:

给你n个数,其中有且仅有一个数出现了奇数次,其余的数都出现了偶数次。用线性时间常数空间找出出现了奇数次的那一个数。

(1)异或

经过上面的介绍,应该想到异或

一个数跟自己偶数次异或是0

奇数次异或是自己


问题4:

给你n个数,其中有且仅有两个数出现了奇数次,其余的数都出现了偶数次。用线性时间常数空间找出出现了奇数次的那两个数。

看看问题2和3中用异或的方法,应该知道答案了吧?

链接:http://blog.csdn.net/neo_ustc/article/details/7324889

【zz】面试题之寻找丢失的数字的更多相关文章

  1. Java实现蓝桥杯历届试题回文数字

    历届试题 回文数字 时间限制:1.0s 内存限制:256.0MB 提交此题 问题描述 观察数字:12321,123321 都有一个共同的特征,无论从左到右读还是从右向左读,都是相同的.这样的数字叫做: ...

  2. 剑指Offer面试题:32.数字在排序数组中出现的次数

    一.题目:数字在排序数组中出现的次数 题目:统计一个数字在排序数组中出现的次数.例如输入排序数组{1,2,3,3,3,3,4,5}和数字3,由于3在这个数组中出现了4次,因此输出4. 二.解题思路 2 ...

  3. 【剑指offer 面试题38】数字在排序数组中出现的次数

    思路: 利用二分查找,分别查找待统计数字的头和尾的下标,最后做差加一即为结果. C++: #include <iostream> #include <vector> using ...

  4. 【剑指offer】面试题38:数字在排序数组中出现的次数

    题目: 统计一个数字在排序数组中出现的次数. 思路: 对二分查找进行改进,找到数字在数组中第一次出现和最后一次出现的位置,这样就得到它出现的次数. 以找第一次出现的位置为例:如果mid元素大于k,则在 ...

  5. 基于visual Studio2013解决面试题之0802数字最多元素

     题目

  6. NOIP2010-普及组复赛模拟试题-第二题-数字积木

    题目描述 Description 小明有一款新式积木,每个积木上都有一个数,一天小明突发奇想,要是把所有的积木排成一排,所形成的数目最大是多少呢?你的任务就是读入 n 个数字积木,求出所能形成的最大数 ...

  7. MT2018笔试题之计算数字位数

    一.计算数字位数 1.题目 给定一个数字T,计算从1到T的所有正整数的位数和.比如T=13,则12345678910111213有17位数字. 输入描述 3 13 4 5 输出 17 4 5 2.思路 ...

  8. C++版 - 剑指offer面试题38:数字在已排序数组中出现的次数

    数字在已排序数组中出现的次数 提交网址: http://www.nowcoder.com/practice/70610bf967994b22bb1c26f9ae901fa2?tpId=13&t ...

  9. [LintCode] Find the Missing Number 寻找丢失的数字

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

随机推荐

  1. 教你一招:Win10系统如何正确卸载edge浏览器?

    Edge浏览器作为Win10系统默认浏览器,尽管我们将其他浏览器设置为默认程序,但是有时候还是会自动弹出,非常的不爽,但是在控制面板中却又找不到卸载“Edge”浏览器的选项.下面小编就教大家卸载“Ed ...

  2. the pipeline of call SNP

    ######################################## ############### Mapping ################ ################## ...

  3. mac 常用地址

    1.hosts   配置文件地址 /private/etc/hosts 2.apache 配置文件地址 /etc/apache2/httpd.conf 3.Xcode 插件地址 ~/Library/A ...

  4. web前端基础知识-(二)CSS基本操作

    1. 概述 css是英文Cascading Style Sheets的缩写,称为层叠样式表,用于对页面进行美化. 存在方式有三种:元素内联.页面嵌入和外部引入,比较三种方式的优缺点. 语法:style ...

  5. QQ等级表

    什么是QQ等级呢? 2003年,腾讯公司推出了QQ等级制度 . 最早是以小时,来计算的,那段时间,绝大部分QQ用户都在挂QQ,之后就有不少媒体指责其浪费能源,在有关部门的介入下,腾讯公司将QQ等级变为 ...

  6. Windows中创建桌面快捷方式

    Windows中创建桌面快捷方式 -------------- -------------- -------------- --------------

  7. [Unity3D]导入模型并且设置相应的属性

    将资源拷贝到Assets中并设置 首先确保法线贴图的属性如下: 设置基本贴图和法线贴图 因为要发布到移动端,设置shader属性: 为了设置更好的反光效果,添加cubemap: 添加新的Materia ...

  8. VirtualBox Guest Additions 在CentOS中无法安装的解决方法

    安装时出现一步错误查看log为(log文件是 /var/log/vboxadd-install.log): /tmp/vbox.0/Makefile.include.header:94: *** Er ...

  9. .net中c#获取本机IP地址实例代码

    * 在使用前,一定要注意在头部加上引用: using System.Net; 代码如下: using System; using System.Collections.Generic; using S ...

  10. C# 的界面控件属性修改线程安全问题

    今天在实验delegate与thread 在初步的实验结束后,因为原来的delegate只有一个函数会被调用,感觉没有达到delegate的极致,所以又重新自己定义了一个delegate,在另一个线程 ...