【数据结构】位运算(一)LeetCode找数组中只出现一次的元素题型总结(Java)

来自LeetCode 136、137、260
除了某k个元素只出现一次以外,其余每个元素均出现m次。找出那个只出现了k次的元素

O、位运算技巧用法总结

  1. 向下整除 n / 2 等价于 右移一位 n >> 1
  2. 判断奇偶时,取余数 n%2 等价于 判断二进制最右一位值 n & 1
  3. (n−1) : 二进制数字 n 最右边的 1 变成 0 ,此 1 右边的 0 都变成 1 。
  4. n & (n−1) : 二进制数字 n 最右边的 1 变成 0 ,其余不变。
  5. 异或运算(二进制x):x ^ 0 = x​x ^ 1 = ~x
  6. 与运算(二进制x):x & 0 = 0x & 1 = x
  7. 异或运算可以帮助我们消除出现偶数次的数字。0 与任何数 XOR 结果为该数;两个相同的数 XOR 结果为 0。则只有某个位置的数字出现奇数次时,该位的掩码才不为 0。我们计算 bitmask ^= x,则 bitmask留下的就是出现奇数次的位。
  8. x & (-x) 保留位中最右边 1 ,且将其余的 1 设为 0。
  9. i >> j & 1 : i的第j位是否是1
  10. n的二进制表示中第k位是几:n >> k & 1

一、某个元素只出现一次以外,其余每个元素均出现两次(k=1,m=2)

思路一:位运算

所有的数字异或,剩下的就是出现次数为奇数次的那个数字。

class Solution {
   
    public int singleNumber(int[] nums) {
   
        int ans = 0;
        for(int num : nums){
   
            ans ^= num;
        }
        return ans;
    }
}

二、某个元素只出现一次以外,其余每个元素均出现三次(k=1,m=3)

思路一:位运算,遍历统计

统计所有数字的各二进制位中 1 的出现次数,并对 3求余,结果则为只出现一次的数字。按位遍历统计。

此方法可扩展到k=1,m取任何值的情况。

class Solution {
   
    public int singleNumber(int[] nums) {
   
        int[] counts = new int[32];
        for(int num : nums){
   
            //每个数字都有32位
            for(int j = 0; j < 32; j++){
   
                //更新第j位,即这个数字的第j位是0还是1,写到counts里
                counts[j] += num & 1;
                //无符号右移,第j位到第j+1位
                num >>>= 1;
            }
        }
        int res = 0;
        // 修改求余数值m,即可实现解决除了一个数字以外,其余数字都出现m次的通用问题
        int m = 3;
        for(int i = 0; i < 32; i++){
   
            res <<= 1;
            //只出现一次的数字的第(31 - i)位,恢复到res中
            res |= counts[31-i] % m;
        }
        return res;
    }
}
思路二:有限状态自动机

参考
出现三次的数字,各 二进制位出现的次数都是3的倍数。用two(高位),one(低位)来表示对3取余的这三个状态。
因为相同的数字某一位是0或者1的情况是相同的。对一位来看,来一个数字,如果该位是1,则从00—>01,再来一个数字,如果新数字的该位还是1,则01—>10。

  • 关于状态转换公式的推导
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值