您的位置:首页 > 其它

寻找数组中丢失的、者重复的、或者出现一次的的数的问题汇总

2014-12-22 18:18 323 查看
1. 集合增量问题

一组大小为1到n的牌,抽走一张,求抽走的是哪张牌?

此类问题特点:

输入:1)已知原始集合:或者是直接给定一个数组,或者是给一个描述,比如1到n,每个数出现一次(或2次),总之原始集合是确定的

2)改变后的集合:原始集合拿走(添加)一个或2个数之后的集合

求:少了的数,多出来的数等,其实就是求两个集合的增量

思路:题目所求就是求2个集合之间的增量(差异),所以思路就是“求差”,对原始集合求和,减去当前集合的和,就是多出来或者缺失的数;如果是少了2个数怎么办?多算一种差异,平方和的差,联列x+y= a, x^2+y^2 = b 解方程。理论上几个数都可以,既增加数,又减少数也可以,因为都是解方程,就是变量个数和方程形式的问题。

少了2个数,多了2个数,少了一个数,同时一个数多出现了一个,少了一个数,多了一个数(这个数不属于集合),这些问法都是一样的。

如果元素是连续的,可以映射到下标,则可以用桶排序思想

大小为n的数组,元素是1到n的数,但是少了一个数,同时一个数多出现了一次,求这两个数。

桶排序,尝试把每个数组元素a[i] 放在它应该出现的位置,如果那个位置已经是这个数了,说明这个数重复了;i++。最后从前往后再扫一遍,第一个位置上不是对应数的位置就是缺失的数。

2. Single number 问题,其他数都出现了k(k>1)次,只有一个数出现了一次,求这个数

分析:如果原始集合是已知的,依然可以使用2集合求差异的方法,(原始和 -  实际和 ) /( k-1) 即为所求。但这里原始集合不是给定的,需要统计unique的数,需要一个set,那还不如用最基本的map计数法。

换一种思路:考虑把出现了多次数消掉,如果k是偶数,则可用异或法;如果k是奇数,则可以用求和再求余法,出现k次的数模k为0,和里最终剩下的是那个single number %k,还是不行,再利用一个性质,小于k的数对k取模就是这个数本身,分别求single number的每一位

int singleNumber(vector<int>& nums) {
    vector<int> B(32);
    int res = 0;
    for (int j = 0; j < 32; ++j) {//compute each bit of the result number and then add into the result
        for (int i = 0; i < nums.size(); ++i) B[j] += (nums[i] >> j) & 1; // B[j]: sum of bit j;
        res |= (B[j] % 3) << j;
    }
    return res;
}

3 另一种single Number问题,但变化的是single number的个数

一般的数都出现2次(或者偶数次)只有k个数只出现一次。求这k个只出现一次的数。如果k = 1,直接异或法;如果k=2,先异或,找一个为1的bit位,按这一位是0还是1把所有的数分成2部分,两个出现一次的数分别在这两部分,然后各自异或法求。

如果k = 3。首先要明确3点:1)数组总数一定是奇数,2)3个不同的数异或结果有可能是0,3)两个不同的数异或必然不为0。

按第0位是0还是1分成两组,必然一个组个数是奇数一个组个数是偶数。这三个数中,偶数组要么有2个,要么没有,不能有3个或1个。所以偶数组异或为0,则说明三个数都在奇数组,递归问题。若偶数组异或不为0,则说明有两个在其中,异或奇数组得到一个数。偶数组变成k= 2的 single Number问题。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐