面试题1:找出一个数组中三个只出现一次的数字

version1: 找出一个数组中一个只出现一次的数字,其他数字都出现两次:将所有数字异或,得到的结果即为只出现一次的。

version2: 找出一个数组中两个只出现一次的数字,其他数字都出现两次:将所有数字异或,得到的结果即为x=a^b, index为x中第一个为1的位,则a 和b中第index为必然有一个为1,有一个为0。据此将所有数据分为两组,一组的第index为都为1,另一组第index为都为0,第一组数字异或得到a,第二组数字异或得到b.

时间复杂度为o(n),空间复杂度为o(1)。

(判断某一位是否为1:int result=a&(1<<i))若结果不为0,则a的第i位为1;否则第i位为1。

version3:找出一个数组中三个只出现一次的数字,其他数字都出现两次:将所有数字异或,得到的结果为x=a^b^c。x必然与a,b,c都不相同,因此x^a,x^b,x^c都不为0.

定义函数f(n),作用是保留数字n的二进制表示中最后一位1,而其他位都变为0. 则f(x^a),f(x^b),f(x^c)的结果均不为0.

考虑f(x^a)^f(x^b)^f(x^c)的结果,它肯定不为0。因为对于三个非零的数i,j,k, f(i)^f(j)的结果要么为0,要么结果的二进制结果中有两个是1,而f(k)的结果中只有一位是1,所以f(i)^f(j)^f(k)一定不为0。

因此f(x^a)^f(x^b)^f(x^c)至少有一位为1,假设最后一位是1的位为第 m 位。那么x^a, x^b, x^c的结果中,有一个或者三个数字的第m位是1.

下面证明不可能三个结果的第m位都是1. 反证法证明:若x^a,x^b, x^c的第m位都是1,则a,b,c的第m位都和x的第m位相反,那么a,b,c的第m位相同。若都为0,则x=a^b^c的第m为也未0,与x的第m位与a,b,c第m位相反矛盾;同样若都为1,则x第m位为1,与假设矛盾。因此a,b,c中只有一个数字的第m位为1。 于是我们找到了区分a,b,c三个数字的标准。一旦将第m位为1的数找出来之后,另外两个数字也可以找出来了。

version4: 一个数组中除了一个数字出现一次外,其他数字都出现了三次,找出只出现了一次的数字。

思路:若数组中没有x,则其他所有数字都出现了三次,那么所有数字的二进制表示的每一位相加都应该可以被3整除,如果某一位不能,则表明x在这一位上是1。 这种解决方案可以扩展到其他所有数字都出现了N次的情形。

代码:

// 【白话经典算法系列之十七】<span >数组中只出现一次的数</span>

// by MoreWindows( http://blog.csdn.net/MoreWindows )

// 欢迎关注http://weibo.com/morewindows

#include <stdio.h>

#include <string.h>

int FindNumber(int a[], int n)

{

int bits[32];

int i, j;

// 累加数组中所有数字的二进制位

memset(bits, 0, 32 * sizeof(int));

for (i = 0; i < n; i++)

for (j = 0; j < 32; j++)

bits[j] += ((a[i] >> j) & 1);

// 如果某位上的结果不能被整除,则肯定目标数字在这一位上为

int result = 0;

for (j = 0; j < 32; j++)

if (bits[j] % 3 != 0)

result += (1 << j);

return result;

}

int main()

{

printf(" 【白话经典算法系列之十七】数组中只出现一次的数\n");

printf(" -- by MoreWindows( http://blog.csdn.net/MoreWindows ) --\n");

printf(" -- http://blog.csdn.net/morewindows/article/details/12684497 -- \n\n");

const int MAXN = 10;

int a[MAXN] = {2, 3, 1, 2, 3, 4, 1, 2, 3, 1};

printf("%d\n", FindNumber(a, MAXN));

return 0;

}

时间: 2024-08-06 11:35:29

面试题1:找出一个数组中三个只出现一次的数字的相关文章

算法题:找出整数数组中两个只出现一次的数字

问题:一个整数数组里除了两个数字之外,其他的数字都出现了两次.请写程序找出这两个只出现一次的数字.要求时间复杂度为O(n),空间复杂度为O(1). 分析:这是一个很新颖的关于位运算的题目. 首先考虑这个问题的一个简单版本:一个整数数组里除了一个数字之外,其他的数字都出现两次,请写程序找出这个只出现一次的数字. 这个问题的突破口在哪?题目中数组的性质是只有一个整数出现一次,其他的都出现两次.这样的话就使我们想到了异或运算的性质:任何一个数字异或它自己都等于0.也就是说如果从头到尾依次异或数组中的每

程序员面试100题之十:快速找出一个数组中的两个数字,让这两个数字之和等于一个给定的值(转)

能否快速找出一个数组中的两个数字,让这两个数字之和等于一个给定的值,为了简化起见,我们假设这个数组中肯定存在至少一组符合要求的解. 假如有如下的两个数组,如图所示: 5,6,1,4,7,9,8 给定Sum= 10 1,5,6,7,8,9 给定Sum= 10 分析与解法 这个题目不是很难,也很容易理解.但是要得出高效率的解法,还是需要一番思考的. 解法一 一个直接的解法就是穷举:从数组中任意取出两个数字,计算两者之和是否为给定的数字. 显然其时间复杂度为N(N-1)/2即O(N^2).这个算法很简

算法题:找出一个数组中依次最大的k个元素

package arithmetic; import java.util.Arrays; /** * 找出一个数组中依次最大的k个元素 * @author SHI */ public class FindMaxFigure { public static void main(String[] args) { int[] a=new int[]{1,5,-1,8,0,2}; System.out.println(Arrays.toString(findBigFigure(a, 3))); } /*

1152: 零起点学算法59——找出一个数组中出现次数最多的那个元素

1152: 零起点学算法59--找出一个数组中出现次数最多的那个元素 Time Limit: 1 Sec  Memory Limit: 64 MB   64bit IO Format: %lldSubmitted: 990  Accepted: 532[Submit][Status][Web Board] Description 找出一个数组中出现次数最多的那个元素 Input 第一行输入一个整数n(不大于20) 第二行输入n个整数 多组数据 Output 找出n个整数中出现次数最多的那个整数(

算法题:找出一个数组中相加值最大的连续序列元素

package arithmetic; /** * @author SHI * 求一个数组中相加值最大的连续序列元素 */ public class MaxSequence { public static void main(String[] args) { int[] a=new int[]{-2,9,-3,4,-6,7,-6,4}; findBigSequence(a); } /** * 思想: (1)计算出该数组的所有元素和,假设该值为最大 * (2)从数组下标1到a.length-1依次

找出一个数组中出现次数最多的那个元素

#include <stdio.h> int main() { int n,a[20],i,j,flag=0,max; int b[20]={0}; while(scanf("%d",&n)==1){ if(n==0) break; for(i=0;i<n;i++) scanf("%d",&a[i]); for(i=0;i<n-1;i++) for(j=i+1;j<n;j++) if(a[i]==a[j]) b[i]++

算法试题 - 找出一个序列中出现频率最高的三个数

题目 找出一个序列中出现频率最高的三个数 解析 思路一 创建一个新字典, k 为 序列的值, 然后 v 的初始值 0, 然后循环序列进行计数, 然后进行新字典的处理..... 不行, 不好处理了. 此思路不行 思路二 利用 colletctions 的 Counter 模块, 内部有个方法可以解决 k 值问题 答案 答案一 可以往下继续实现, 但是有点麻烦了 li = [2, 5, 3, 4, 1, 8, 1, 2, 6, 6, 1, 5, 1, 5] d = dict.fromkeys(li,

【编程题目】找出数组中两个只出现一次的数字 ★★(自己没做出来)

61.找出数组中两个只出现一次的数字(数组)题目:一个整型数组里除了两个数字之外,其他的数字都出现了两次.请写程序找出这两个只出现一次的数字.要求时间复杂度是 O(n),空间复杂度是 O(1). 思路:瞄到了一眼提示,说是位运算. 根据异或的运算性质: a ⊕ b ⊕ a = b 把所有的数字都异或一遍得到的结果就是 那两个只出现一次的数字异或的结果. 可怎么分出那两个数字就卡住了. 看了下网上答案,要根据得到的异或值把数字分为两组,再对每一组异或就可以得到这两个数字了! 代码如下: /* 61

找出一个字符串中最长重复次数的子字符串,并计算其重复次数

原题 找出一个字符串中最长重复次数的子字符串,并计算其重复次数.例如:字符串"abc fghi bc kl abcd lkm abcdefg",并返回"abcd"和2. 我的思路 为了方便表述,我们使用变量src作为原字符串,sub_str作为子字符串. 由于题目要求寻找至少重复2次的最长的子字符串,重点在于最长的子字符串,而不在于重复的最多次数.因此我们可以从长度最长的字符串入手,计算其重复次数.只要重复达到2次,即可返回该字符串. 显然长度最长的子字符串就是原串