刷题:技巧-位运算

二进制的三种表示形式:原码、反码、补码

二进制转化为十进制:从左起第一个数字开始 2的零次方+2的1次方......

原码:即二进制表示,最高位是符号位,0代表正数,1代表负数,在位运算中符号位也参与运算。

反码:正数的反码就是其原码本身,负数的反码是符号位不变,其余位取反,也就是0变1,1变0.

补码:正数的补码仍是原码,负数的补码是反码+1。计算机内部使用补码表示。

二进制的计算

按位非操作~

~1 = 0

~0 = 1

~把num的补码中0和1全部取反,有符号整数的符号位在~运算中同样会取反。

按位与操作&

全是1即为1,有一个0即为0。

1&1 = 1

1&0 = 0

0&1 = 0

0&0 = 0

按位或操作|

只要有两个对应位中有一个1时就为1。

1|1 = 1

1|0 = 1

0|1 = 1

0|0 = 0

按位异或操作

只有两个对应位不同时才为1。

异或操作满足交换律和结合律。

1^1 = 0

1^0 = 1

0^1 = 1

0^0 = 0

A^A = 0

A^0 = A

按位左移操作<<

num << i 将num的二进制表示左移动 i 位所得的值。即前面去掉i位,后面用0补位。

num左移动i位后,十进制num变成了num*2的i次方。

按位右移操作>>

num>>i将num的二进制表示向右移i位所得的值。即后面去掉i位,前面用0补位。

num右移i位后,十进制num变成了num//2的i次方。

案例

只出现一次的数字

数字之间的异或:0^A=A

class Solution:
    def singleNumber(self, nums: List[int]) -> int:
        result = 0
        for i in nums:
            result ^=  i
        return result

只出现一次的数字Ⅲ

思路:

1)先整体做一次异或得到一个数字A;

2)再想办法将两个不一样的数字从第一个数字中分离出来,即A&A得到其中一个数字B,B再分别与其它数字进行&的操作,此时能够将所有数字分成两组,每一组中都有存在一个只出现过一次的数字。

3)分别对两组数字进行异或操作。

class Solution:
    def singleNumber(self,nums:List[int]) -> List[int]:
        if len(nums)<2:
            return []
        different = 0
        for num in nums:
            different ^= num
        different &= -1*different
        num1 = 0
        num2 = 0
        for num in nums:
            if (num & different ) == 0:
                num1 ^= num
            else:
                num2 ^= num
        return [num1,num2]

任务

2的幂

思路:枚举

class Solution:
    def isPowerOfTwo(self, n: int) -> bool:
       return n > 0 and n & (n - 1) == 0

子集

集合中每个元素都可以选或不选。

java

class Solution {
    public List<List<Integer>> subsets(int[] nums) {
        List<List<Integer>> res = new ArrayList<List<Integer>>();
        for (int i = 0; i < (1 << nums.length); i++) {
            List<Integer> sub = new ArrayList<Integer>();
            for (int j = 0; j < nums.length; j++)
                if (((i >> j) & 1) == 1) sub.add(nums[j]);
            res.add(sub);
        }
        return res;


    }
}

只出现一次的数字

思路:java

 

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++) {
              //先将数右移,并求出最后一位为 1 的个数
              if ((nums[j] >> i & 1) == 1) {
                  count++;
              }             
          }
          //找到某一位取余为 1 的数,并左移,为了将这一位循环结束后移至原位
          if (count % 3 != 0) {
              res = res | 1 << i;
          }
      }
      return res;       
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值