leetcode位操作例题

位操作

位操作(Bit Manipulation)是程序设计中对位模式或二进制数的一元和二元操作。常用的位操作有:

  • 消除数字 n 的二进制表示中的最后一个1
    n & (n - 1)

  • 获得数字n的最低非0位
    n & (-n)

  • 常见的移位操作

1. 数组中只出现一次的数字

例题描述: 给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

思路: 利用位操作中的异或操作来完成,异或操作:相同为0,不同为1,所以数组中所有相同的数经过异或后统统变为0,而不同的数会留下来。

示例: 数组 a = [0, 0, 1, 1, 2],数组中的两个0和两个1经过异或后变为0,0和任何数字异或结果都为那个数字。

代码:

class Solution {
    public int singleNumber(int[] nums) {
        int res = 0;
        for (int i = 0; i < nums.length; i++) {
            res ^= nums[i];
        }
        return res;
    }
}

2. 只出现一次的数字 II

例题描述: 给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现了三次。找出那个只出现了一次的元素。
**思路:**当一个数字出现3次时,那么它的二进制位必定是3的倍数,如果它的二进位不是3的倍数,那么肯定是出现一次的那个数字使之不为3的倍数。
示例:
假如例子是 1 2 6 1 1 2 2 3 3 3, 3 个 1, 3 个 2, 3 个 3,1 个 6
1 0 0 1
2 0 1 0
6 1 1 0
1 0 0 1
1 0 0 1
2 0 1 0
2 0 1 0
3 0 1 1
3 0 1 1
3 0 1 1
看最右边的一列 1001100111 有 6 个 1
再往前看一列 0110011111 有 7 个 1
再往前看一列 0010000 有 1 个 1
我们只需要把是 3 的倍数的对应列写 0,不是 3 的倍数的对应列写 1
也就是 1 1 0,也就是 6。

**代码: **

class Solution {
    public int singleNumber(int[] nums) {
        int res = 0;
        for (int i = 0; i < 32; i++) {
            int count = 0;
            for (int j = 0; j < nums.length; j++) {
                if ((nums[j] >>> i & 1) == 1) {
                    count++;
                }
            }
            if (count % 3 != 0) {
                res = res | 1 << i;
            }
        }
        return res;
    }
}

3. 只出现一次的数字 III

例题描述: 给定一个整数数组 nums,其中恰好有两个元素只出现一次,其余所有元素均出现两次。 找出只出现一次的那两个元素。
**思路: ** 我们可以将这一整数数组拆分成两部分,每一部分的数组都只有一个元素出现过一次,那么该问题就转换成第一题中的问题,所以问题的关键在于如何进行分组。该分组共有三个步骤:

  1. 把所有的元素进行异或操作,最终得到一个异或值。因为是不同的两个数字,所以这个值必定不为0;
int mask = 0;
for (int i = 0; i < nums.length; i++) {
    mask ^= nums[i];
 }
  1. 取异或值最后一个二进制位为1的数字作为mask,如果是1则表示两个数字在这一位上不同。
    int mask = mask & (-mask);

  2. 通过与这个mask进行与操作,如果为0的分为一个数组,为1的分为另一个数组。这样就把问题降低成了:“有一个数组每个数字都出现两次,有一个数字只出现了一次,求出该数字”。对这两个子问题分别进行全异或就可以得到两个解。也就是最终的数组了。

代码:

class Solution {
    public int[] singleNumber(int[] nums) {
        int[] res = new int[2];
        int mask = 0;
        for (int i = 0; i < nums.length; i++) {
            mask ^= nums[i];
        }
        // a & (-a) 可以获得a最低的非0位
        mask = mask & (-mask);
        for (int i = 0; i < nums.length; i++) {
            if ((nums[i] & mask) == 0) {
                res[0] ^= nums[i];
            } else {
                res[1] ^= nums[i];
            }
        }
        return res;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值