落单的数

题目一:给出2*n + 1 个的数字,除其中一个数字之外其他每个数字均出现两次,找到这个数字。
例子:给出 [1,2,2,1,3,4,3],返回 4。
挑战:一次遍历,常数级的额外空间复杂度。

方法:可以用排序或hash 解决。排序以后,对每个坐标i,查找A[i-1], A[i+1]中是否有等于A[i]的,没有则为要找的数。或者用hash table/set来记录扫描过的数字。如果A[i]不在hash table中,则插入,如果已经在,则在hash table中删除,最后table中剩下的就是要找的数。但排序法事件复杂度是O(nlogn),而hash table尽管是O(n)事件复杂度,需要o(n)的extra memory。

这题的终极解法是利用位运算中的异或:x^x = 0, x^0 = x。并且异或有交换律:1^1^0 = 0 = 1^0^1。所以如果将全部数字进行异或运算,所有重复元素都会被消除,最后的结果便是那个唯一的数。

class Solution {
public:
    int singleNumber(int A[], int n) {
        int res = 0;
        for(int i=0; i<n; i++) 
            res ^= A[i];
        return res;        
    }
};

题目二:给出3*n + 1 个的数字,除其中一个数字之外其他每个数字均出现三次,找到这个数字。
例子:给出 [1,1,2,3,3,3,2,2,4,1] ,返回 4。
挑战:一次遍历,常数级的额外空间复杂度。

方法
由于x^x^x = x,无法直接利用I的方法来解。但可以应用类似的思路,即利用位运算来消除重复3次的数。以一个数组[14 14 14 9]为例,将每个数字以二进制表达:

1110
1110
1110
1001

4331
对每一位进行求和
1001
对每一位的和做%3运算,来消去所有重复3次的数。

class Solution {
public:
    int singleNumber(int A[], int n) {
        int res = 0;
        for(int i=31; i>=0; i--) {
            int sum = 0;
            int mask = 1<<i;
            for(int j=0; j<n; j++) {
                if(A[j] & mask) 
                    sum++;
            }
            res = (res<<1) + (sum%3);
        }
        return res;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值