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

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) {
    int ans = 0;
    for (int i = 0; i < 32; ++i) {
        int b = 0;
        for (int x: A) {
            b += (x >> i) & 1;
        }
        ans |= (b % 3) << i;
    }
    return ans;
}

 

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问题。

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值