菜鸟系列之C/C++经典试题(九)

寻找数组中出现的唯一重复的一个数

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

方法一:(当N为比较大时警惕溢出)将1001个元素相加减去1,2,3,……1000数列的和,得到的差即为重复的元素。

int findRepeat(int *a)
{
    int   i;
    for (i = 0; i < 1001; i++)
    {
        a[1000] += a[i];
    }

    a[1000] -= (i*(i - 1)) / 2;       //i的值为1001
    return   a[1000];
}

方法二:

原理:

设重复数为A,其余999个数异或结果为B。

1001个数异或结果为A^A^B

1-1000异或结果为A^B

由于异或满足交换律和结合律,且A^A = 0  0^A = A;

则有

(A^B)^(A^A^B)=A^B^B=A

实现代码如下:

int findRepeat(int *src, int n)
{
    for (int i = 1; i < n; ++i)
    {
        src[0] ^= (src[i] ^ i);
    }
    return src[0];
}

其中:src位存放数的数组, 你为数组元素的个数,在循环里面src[0] = src[0] ^ src[1]^...^src[n-1] ^ 1 ^ 2 ^ ...^ (n-1)

若是可以使用辅助空间, 我则会这么些上面的代码:

int findRepeat(int *src, int n)
{
    register int result = src[0];

    for (int i = 1; i < n; ++i)
    {
        result ^= (src[i] ^ i);
    }
    return result;
}

若有不清楚, 可以与我联系, 如有错误, 欢迎指出, 分享请表明出处, 谢谢

感觉好的话就顶一个, 感觉不错的话就踩一个。

时间: 2024-10-14 16:08:43

菜鸟系列之C/C++经典试题(九)的相关文章

菜鸟系列之C/C++经典试题(三)

设计包含min函数的栈 题目:定义栈的数据结构,要求添加一个min函数,能够得到栈的最小元素.要求函数min.push以及pop的时间复杂度都是O(1). 分析:这是2006年google的一道面试题. 我看到这道题目时,第一反应就是每次push一个新元素时,将栈里所有逆序元素排序.这样栈顶元素将是最小元素.但由于不能保证最后push进栈的元素最先出栈,这种思路设计的数据结构已经不是一个栈了. 在栈里添加一个成员变量存放最小元素(或最小元素的位置).每次push一个新元素进栈的时候,如果该元素比

菜鸟系列之C/C++经典试题(一)

这个我写菜鸟系列之C/C++ 的第一篇文章 题目:输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表.要求不能创建任何新的结点,只调整指针的指向. 比如将二元查找树 10 /    \ 6       14 /  \     / \ 4     8  12   16 转换成双向链表 4=6=8=10=12=14=16. 分析:本题是微软的面试题.很多与树相关的题目都是用递归的思路来解决,本题也不例外.下面我们用两种不同的递归思路来分析. 思路一:当我们到达某一结点准备调整以该结点为根结点

菜鸟系列之C/C++经典试题(二)

求子数组的最大和 题目描述: 输入一个整形数组,数组里有正数也有负数.数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和.求所有子数组的和的最大值.要求时间复杂度为O(n). 例如输入的数组为1, -2, 3, 10, -4, 7, 2, -5,和最大的子数组为3, 10, -4,7, 2,因此输出为该子数组的和18. 这个问题在各大公司面试中出现频率之频繁,被人引用次数之多,非一般面试题可与之匹敌.ok,下面,咱们来一步一步分析这个题. 分析与解法 解法一 求一个数组的最大子数组和

菜鸟系列之C/C++经典试题(四)

题目一:查找最小的k个元素 输入n个整数,输出其中最小的k个. 例如输入1,2,3,4,5,6,7和8这8个数字,则最小的4个数字为1,2,3和4. 分析:这道题最简单的思路莫过于把输入的n个整数排序,这样排在最前面的k个数就是最小的k个数.只是这种思路的时间复杂度为O(nlogn).我们试着寻找更快的解决思路. 我们可以先创建一个大小为k的数据容器来存储最小的k个数字.接下来我们每次从输入的n个整数中读入一个数.如果容器中已有的数字少于k个,则直接把这次读入的整数放入容器之中:如果容器中已有k

菜鸟系列之C/C++经典试题(十)

打印1到最大的n位数 题目:输入数字n,按顺序打印出从1到最大的n位十进制数.比如输入3,则打印1, 2, 3,-,999. 方法一: 这道题一看感觉很简单,首先求的n位数的最大值,然一个从1到这个最大值的循环就搞定了, 如果真的就把这样的答案面试官的话, 后果很是严重.首先, 没有考虑到获得的这个最大的数会不会溢出,如果溢出了, 答案肯定不对.这个代码比较简单, 我就不列出来了. 方法二: 很明显, 这道题我们可以用递归做, 就是每当多添加一位时, 我就把所以的都打印一遍连带刚添加的这个位,

菜鸟系列之C/C++经典试题(六)

含有指针成员的类的拷贝 题目:下面是一个数组类的声明与实现.请分析这个类有什么问题,并针对存在的问题提出几种解决方案. template<typename T> class Array { public: Array(unsigned arraySize) :data(0), size(arraySize) { if (size > 0) data = new T[size]; } ~Array() { if (data) delete[] data; } void setValue(u

菜鸟系列之C/C++经典试题(七)

找含单链表的环入口点 问题1:如何判断单链表中是否存在环(即下图中从结点E到结点R组成的环)? 分析:设一快一慢两个指针(Node *fast, *low)同时从链表起点开始遍历,其中快指针每次移动长度为2,慢指针则为1.则若无环,开始遍历之后fast不可能与low重合,且fast或fast->next最终必然到达NULL:若有环,则fast必然不迟于low先进入环,且由于fast移动步长为2,low移动步长为1,则在low进入环后继续绕环遍历一周之前fast必然能与low重合(且必然是第一次重

菜鸟系列之C/C++经典试题(五)

求圆圈中剩下的最后一个数字 题目:n个数字(0,1,-,n-1)形成一个圆圈,从数字0开始,每次从这个圆圈中删除第m个数字(第一个为当前数字本身,第二个为当前数字的下一个数字).当一个数字删除后,从被删除数字的下一个继续删除第m个数字.求出在这个圆圈中剩下的最后一个数字. 本题就是著名的约瑟夫环问题. 本题的解法我们比较容易想到用链表,当然我们可以自己写一个链表,也可以直接用stl库中的list,实现代码如下: //使用标准库 int JosephusProblem_Solution2(int

菜鸟系列之C/C++经典试题(八)

计算二进制中1的个数 题目:位运算方面的编程很少遇到,但也是很重的一个只是点,一个比较常见的题目就是计算一个数的二进制表示中的1的个数. 分析:一个1都没有就是0, 我们的思路就是一位一位的运算, 我们很快就想到下面的做法: int countBit1(int val) { register int count = 0; while (val) { if (1 & val) { ++count; } val >>= 1; } return count; } 砟一看这个实现不错, 仔细看