LintCode 第82题 落单的数 【贪心算法】

来源:互联网 发布:ftp打开的端口号 编辑:程序博客网 时间:2024/05/29 18:43

题目描述:

给出2*n + 1 个的数字,除其中一个数字之外其他每个数字均出现两次,找到这个数字。

样例

给出 [1,2,2,1,3,4,3],返回 4

解题思路:

其实这道题,刚开始拿到你可能会觉得是在考查找算法。可能还会想到二分查找,但是这道题 不适用于二分查找,因为里面是有重复数字的,如果使用遍历,写上两个for循环再配合数组去记录已经出现的数字,这样来判断是否是单个的话,其实也是可以,但是时间复杂度很高。

我们可以转化一个思路,使用二进制的位运算,其实很多公司的面试题都考到了位运算,可能平常开发很少用到,不一定会想得到,这里先给不知道的朋友复习一下。

一个十进制数字6如果用二进制来表示是 00000110,一个十进制数字2用二进制来表示是00000010,位运算其实就是针对二进制来做运算。


1.按位取反"~",作用是将数据的二进制每一位都取反操作,即如果当前位是0,则运算后变为1.

2.按位与运算"&",需要两个操作数,作用将两个数相同的位进行逻辑与运算,如果两个数对应位值都为1,则运算后此位结果为1。

3.按位或运算"|" ,需要了两个操作数,作用是将两个数的相同位进行逻辑或运算,即如果两个对应位有一个位1,则运算后此位为1,如果两个对应位都为0.则运算后此位结果为0.

4.按位异或运算符"^",需要两个操作数,作用是将两个数的相同位进行逻辑异或运算。即两个对应位的值相同,则运算后此位的值为0,如果两个对应位的值不同,则运算后结果为1.

5.按位左移运算符"<<",用于将数据每一位上的值进行左移操作。空缺的位用0补齐,考虑位运算后溢出,出现丢失数据位情况。

6.按位右移运算符">>",作用是将数据每一位上的值进行右移操作,空缺的位用0补齐考虑位运算后溢出,出现丢失数据位情况


我们给一个例子就是上面的数字6的二进制00000110和数字2的二进制00000010进行异或运算得出00000100,十进制为数字4.

所以这道题中,数组只有一个数字是单个的,其他都是成对的,如果成对的数执行二进制的异或运算就是0,那么我们可以对所有的 数据挨个进行异或,这样成对的执行完就是0.剩下的那个二进制数字其实就是我们要找的那个数字。


实现代码:

int singleNumber(int a[],int length){    if (length <= 0) {        return 0;    }    int n = a[0];    for (int i = 1; i<length; i++) {        n = n^a[i];    }    return n;}int main(int argc, const char * argv[]) {    // insert code here...    std::cout << "Hello, World!\n";        int a[5] = {6,2,2,1,1};    int value = singleNumber(a,5);    return 0;}