剑指offer---day1

LeetCode(剑指offer) day1

剑指 Offer II 001. 整数除法

题目描述:

给定两个整数 a 和 b ,求它们的除法的商 a/b ,要求不得使用乘号 ‘*’、除号 ‘/’ 以及求余符号 ‘%’ 。

注意:

整数除法的结果应当截去(truncate)其小数部分,例如:truncate(8.345) = 8 以及 truncate(-2.7335) = -2
假设我们的环境只能存储 32 位有符号整数,其数值范围是 [−231, 231−1]。本题中,如果除法结果溢出,则返回 231 − 1

思路:

​ 此题思路在于将除法转换为减法,并转换为减法的思路上进行优化,其减法的思路在于可以对减数不断的乘以2来处理,有点类似于二分法的思想,达到一个临界值,便可开始下一次计算,值得注意的是,此题要求只能为32位有符号数,可以将被除数和除数转换为负数进行处理,避免其数据溢出。而在这个乘以2处理的方式上,可以采用位运算来优化效率。

未利用位运算进行优化

public int divide(int a, int b) {
        if(a == Integer.MIN_VALUE && b == -1){
            return Integer.MAX_VALUE;
        }
        if(a == 0){
            return 0;
        }
        if(b == 1){
            return a;
        }
        boolean flag = false;
        if((a>0 && b>0)||(a<0 && b<0)){
            flag = true;
        }
        int left = a > 0 ? -a : a;
        int right = b > 0 ? -b : b;
        if(left > right){
            return 0;
        }
        int res = 0;
        while (left <= right){
            int value = right;
            int k = 1;
            while (left < value + value){
                value += value;
                k += k;
            }
            left -= value;
            res += k;
        }
        return flag ? res : -res;
    }

利用位运算

public int divide(int a, int b) {
        if(a == Integer.MIN_VALUE && b == -1){
            return Integer.MAX_VALUE;
        }
        if(a == 0){
            return 0;
        }
        if(b == 1){
            return a;
        }
        boolean flag = false;
        if((a>0 && b>0)||(a<0 && b<0)){
            flag = true;
        }
        int left = a > 0 ? -a : a;
        int right = b > 0 ? -b : b;
        if(left > right){
            return 0;
        }
        int res = 0;
        int count = 31;
        while (left <= right){
            while (left >> count >= right ){
                count--;
            }
            left -= right << count;
            res += 1 << count;
        }
        return flag ? res : -res;
    }

位运算

运算符:

& 与 两个位都为1时,结果才为1。

| 或 两个位都为0时,结果才为0。

<< 左移 各二进位全部左移若干位,高位丢弃,低位补0。

>> 右移 各二进位全部右移若干位,对无符号数,高位补0,有符号数,右移补1

^ 异或 两个位相同为0,相异为1。

位运算高级操作:

去掉最后一位 0100−>0010 x>>1

在最后加一个0 0100−>1000 x<<1

在最后加一个1 0100−>1001 x<<1+1

将最后一位变为1 0100−>0101 x|1

将最后一位变为0 0101−>0100,这里实际上就是先确保最低位变为1,再减去1。 x|1-1

最后一位取反 0100−>0101 ,利用异或性质,其中除最后一位其余不变 x∧1

把右数的第k位变为1 0001−>1001,k=4 x|(1<<(k-1))

把右数的第k位变为0 1001−>0001,k=4,这个操作实际上就是先得到了1000,然后取反得到0111,最后利用按位与的性质其余位不变,最高位为0 x&∼(1<<(k−1))

位运算应用:

位运算实现乘除法

将x左移一位实现× 2,将x右移一位实现÷ 2

a < < 1 ≡ a ∗ 2 

a > > 1 ≡ a / 2 

位运算判断奇偶数

我们知道,在二进制中,最低位决定了是奇数还是偶数,所以我们可以提取出最低位的值,即与1相与即可实现目的,为0则是偶数,为1则是奇数。

位运算统计二进制数1的个数

int count(int x){
    int cnt = 0;
    while(x){
        x = x & (x - 1);
        cnt ++;
    }
    return cnt;
}

此处只列举了一些常用的,更多更细请点击下方链接

位运算全面总结

剑指 Offer II 002. 二进制加法

题目描述:给定两个 01 字符串 ab ,请计算它们的和,并以二进制字符串的形式输出。

输入为 非空 字符串且只包含数字 10

思路:用一个中间变量来存储其进位,通过对其进行模2运算获取当前位,进行除2运算获取进位。

public String addBinary(String a, String b) {
        int aLen = a.length();
        int bLen = b.length();
        StringBuilder str = new StringBuilder();
        int i = aLen - 1;
        int j = bLen - 1;
        int carry = 0;
        while (carry == 1 || i >= 0 || j >= 0){
               if(i>=0 && a.charAt(i) == '1'){
                   carry++;
               }
               if(j>=0 && b.charAt(j) == '1'){
                   carry++;
               }
               str.append(carry%2);
               carry/=2;
               i--;
               j--;
        }
        return str.reverse().toString();
    }

剑指 Offer II 003. 前 n 个数字二进制中 1 的个数

题目描述:给定一个非负整数 n ,请计算 0n 之间的每个数字的二进制表示中 1 的个数,并输出一个数组。

思路: 此题主要是利用位运算的性质,即通过n与n-1相与可以消去一个1,当其不能进行消去的时候,便已经统计到其1的个数了。

    public int[] countBits(int n) {
        int[] arr = new int[n + 1];
        for (int i=0 ; i<=n ; i++){
            int index = 0;
            int j = i;
            while (j > 0){
                j &= j-1;
                index++;
            }
            arr[i] = index;
        }
        return arr;
    }
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值