【左神算法笔记】位运算

题目一

给定2个有符号32位整数a和b,返回较大的

要求不要做任何比较判断

借助两个辅助函数,用互斥情况相加得到较大的数:

    // 输入为0或1
    // 1->0
    // 0->1
    public static int flip(int n) {
        return n ^ 1;
    }
    
    // 返回n的符号
    // n为非负数,返回1
    // n为负数,返回0
    public static int sign(int n) {
        return flip((n >> 31) & 1); // n右移31位,得到符号位,与1后,得到返回值的相反数,再flip一下
    }

    public static int getMax1(int a, int b) {
        int c = a - b;
        int scA = sign(c); // a-b非负,该值为1;a-b负,该值为0
        int scB = flip(scA); // 与scA相反
        return a * scA + b * scB;
    }

上面代码可能出现a-b的溢出,改进:

    public static int getMax2(int a, int b) {
        int c = a - b; // 可能溢出
        int sa = sign(a);
        int sb = sign(b);
        int sc = sign(c);
        int diffSab = sa ^ sb; // a和b符号不同,为1;符号相同,为0
        int sameSab = flip(diffSab);
        // a和b符号相同(不会溢出),sc为1,返回a
        // a和b符号不同,且a>0,返回a
        int returnA = diffSab * sa + sameSab * sc; // 两部分互斥,代表两种返回a(a大于b)的情况
        int returnB = flip(returnA);
        return a * returnA + b * returnB;

    }

题目二

判断一个32位正数是否为2的幂、4的幂

是2的幂,则二进制表示中只有一个位是1,判断方式:拿到最右侧的1,计算只有这个位置是1的数,是否与原来的数相等,若相等原来的数就是2的幂

或者计算KaTeX parse error: Expected 'EOF', got '&' at position 2: x&̲(x-1),若结果为0,则x为2的幂

是4的幂,前提是2的幂,即二进制表示中只有一个位是1,并且这个1在第1、3、5······这些位上

所以先判断x是2的幂,然后计算010101···0101&x,若结果为0,不是4的幂,结果不为0,则是4的幂

    public static boolean is2Power(int n) {
        return (n & (n - 1)) == 0;
    }

    public static boolean is4Power(int n) {
        return (n & (n - 1)) == 0 && (n & 0x55555555) != 0;
    }

题目三

给定2个有符号32位整数a和b,不适用算术运算符,完成加减乘除运算

【要求】不考虑给定的ab导致溢出的情况

1、加法

例如:
13:01101
7: 00111
异或^->无进位相加
01010
&并且左移1位->13+7的进位信息
01010

将上述两个结果相加,即为13+7的和

继续用上述步骤计算01010和01010的和

异或得:00000
&并且左移1位:10100

计算00000和10100的和

异或得:10100
&并且左移1位:00000

发现没有进位了,结果就是10100=20

    public static int add(int a, int b) { // 默认不溢出
        int yihuo = 0;
        while (b != 0) {
            yihuo = a ^ b;
            b = (a & b) << 1;
            a = yihuo;
        } // 直到进位信息为0
        return yihuo;
    }

2、减法

a-b=a+(b的相反数)

b的相反数=b取反+1

    public static int minus(int a, int b) {
        return add(a, negNum(b));
    }

    public static int negNum(int b) { // 求b的相反数:取反加1
        return add(~b, 1);
    }

3、乘法

回忆一下小学学的乘法

在这里插入图片描述

    public static int multi(int a, int b) {
        int res = 0;
        while (b != 0) {
            if ((b & 1) != 0) { // 看b的最后一位是1或0
                res = add(res, a);
            }
            a <<= 1; // a左移1位
            b >>>= 1; // 无符号右移,即右移过程中,左边一直补0
        }
        return res;
    }

4、除法

a/b

假设
a=0110110
b=0000101

b左移若干位,尽量移动很多位,但不要大于a

在这里b<<3,相当于乘以8,则a中一定包含1000(2)个b

左移得到b’=0101000

计算a’=a-b’

再使b左移若干位,去逼近a’

在这里b<<2,所以一定包含0100(2)个b

此时a’‘=a’-b’'=0

结束,除法结果为01100

    public static int div(int a, int b) {
        int x = isNeg(a) ? negNum(a) : a;
        int y = isNeg(b) ? negNum(b) : b;
        int res = 0;
        for (int i = 31; i > -1; i = minus(i, 1)) {
            if (((x >> i) >= y)) { // 不直接让y左移,因为有可能移成负数
                res |= (1 << i);
                x = minus(x, y << i);
            }
        }
        return isNeg(a) ^ isNeg(b) ? negNum(res) : res;
    }

    public static boolean isNeg(int n) {
        return n < 0;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值