day 17-18 算法:位运算,统计位1的个数,2的幂次方;比特位计数

1. 题目

  1. 编写一个函数,输入无符号整数,返回二进制表达式中的数字位数为’1’的个数,也称为汉明重量:https://leetcode-cn.com/problems/number-of-1-bits/
  2. 给定一个整数,编写一个函数栏判断它是否是2的幂次方:https://leetcode-cn.com/problems/power-of-two/
  3. 比特位计数:给定一个非负整数num,对于0<=i<=num范围中的每个数字i,计算其二进制数中的1的数目并将它们作为数组返回:https://leetcode-cn.com/problems/counting-bits/

2. 基本知识

2.1 位运算介绍

计算机是用二进制存储和计算的,直接使用二进制进行运算,那么效率会高很多。

10进制转换为二进制:10进制的数除以2取余,再用得到的商除以2再取余,一直循环到商为0,然后将余数按高位到低位排列起来就是二进制数。
6的二进制:110

2.2 位运算常用的操作

  • & : 与,两个位都为1,结果才为1
  • | : 或,两个位都为0,结果才为0
  • ^ : 异或,两个位相同为0,相异为1
  • ~ : 取反,0变1,1变0
  • << : 左移,各二进制位全部左移若干位,低位补0
  • : 右移,各二进制位全部右移若干位,无符号数,高位补0;有符号数,各编译器处理方法不一,有的补符号位(算术右移),有的补0(逻辑右移)

2.3 位运算的应用

2.3.1 异或

x ^ 0 = x 和0做异或运算,x不变
x ^ 1s = ~x ,1s表示位数全为1的数,任何数和1进行异或运算都是取反
x ^ (~x) = 1s
x ^ x = 0 因为每个位数都一样,所以得0

两个数交换
常规写法:

int temp = x;
x = y;
y = temp;

使用异或:

x = x ^ y; // ①
y = x ^ y; // ②
x = x ^ y; // ③

拆解一下(异或支持交换律和结合律的):

  1. ①是初始条件
  2. ②拆解为:y = (x ^ y) ^ y = x^ (y ^ y) = x ^ 0 = x
  3. ③拆解为:x = (x ^ y) ^ x = (x ^ x) ^ y = 0 ^ y = y
2,3,2 与运算

x = x &(x - 1) //清零最低位的1
x & -x // 可以得到最低位的1(并不一定是最后一位)

判断奇偶

%2写法:

x % 2  //结果为1,则x是奇数,结果为0,则x是偶数

与运算写法:

x & 1  //结果为1,则x是奇数,结果为0,则x是偶数

与运算解法拆解一下,6&1=> 110&001,前面的位数不管是0还是1,和0做&运算都是0,则结果为最后一位和1做&运算,得到如上的结果。

3. 算法题解

3.1 编写一个函数,输入无符号整数,返回二进制表达式中的数字位数为’1’的个数,也称为汉明重量

解法1:判断最后一位奇偶,然后左移一位,直到为0
该解法时间复杂度为O(1)(常数次循环),空间复杂度为O(1)

private int hanmingWeight(int n) {
    int sum = 0;

    while (n != 0) {
        if ((n & 1) == 1) {
            sum++;
        }
        n <<= 1;
    }
    return sum;
}

解法2:通过x & (x-1)这个公式,可以把最后一位1置为0,不断循环直到n为0

该解法时间复杂度和空间复杂度都为O(1)

private int hanmingWeight(int n) {
    int sum = 0;

    while (n != 0) {
        n &= (n - 1);
        sum++;
    }
    return sum;
}

3.2 给定一个整数,编写一个函数栏判断它是否是2的幂次方

2的幂次方有一个特点,换成二进制时,所有的位数值只有一个是1,其他为0,而x & (x-1)这个公式可以将最后一个1清零,则有以下的解法。

private boolean isPowerOfTwo(int n) {
    return n > 0 & (n & (n - 1)) == 0;
}

3.3 比特位计数

给定一个非负整数num,对于0<=i<=num范围中的每个数字i,计算其二进制数中的1的数目并将它们作为数组返回

解法1 :循环每个数,找到每个数中1的个数

使用了汉明重量的算法

private int[] countBits(int num) {
    int[] result = new int[num];
    for (int i = 0; i < num; i++) {
        int resultI = hanmingWeight(i);
        result[i] = resultI;
    }
    return result;
}

解法2:

还是用到这个公式:x & (x-1),这个公式可以将最后一个1清零,那么x = x & (x-1) + 1,延伸出来就是 第i个数的1的个数为:count【i】 = count【i & (i - 1)】 + 1(因为i&*(i-1)只去掉最后一个1)

private int[] countBis(int num) {
    int[] result = new int[num];
    result[0] = 0;
    for (int i = 1; i < num; i++) {
        result[i] = result[i & (i - 1)] + 1;
    }
    return result;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值