剑指offer:位运算

文章介绍了如何在编程中不使用常规的加减乘除以及条件判断语句来实现特定的算术运算,如求和、乘积不超过255的计算,以及计算二进制中1的个数。这些方法利用位运算如与(&),或(|),异或(^)以及位移(<<)操作来达到目的,强调了算法的创新性和空间、时间效率。
摘要由CSDN通过智能技术生成

JZ64 求1+2+3+…+n
中等 通过率:43.41% 时间限制:1秒 空间限制:64M
知识点基础数学
描述
求1+2+3+…+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。

数据范围: 0<n≤200
进阶: 空间复杂度 O(1) ,时间复杂度 O(n)
示例1
输入:
5
返回值:
15
示例2
输入:
1
返回值:
1

//短路求值
class Solution {
public:
    int Sum_Solution(int n) {
        n && (n += Sum_Solution(n - 1));
        return n;
    }
};

另一道题:
同样的限制条件,怎么使得两数之积总是小于等于255。
即两个数a和b,如果ab大于255,便返回255,否则返回ab。

int multi(inta, int b)
{  
    int result;  
    (result = (a*b)) > 255 && (result = 255);  
    return result;  
}  

JZ15 二进制中1的个数
简单 通过率:35.79% 时间限制:1秒 空间限制:256M
知识点基础数学
描述
输入一个整数 n ,输出该数32位二进制表示中1的个数。其中负数用补码表示。

数据范围:−231<=n<=231−1
即范围为:−2147483648<=n<=2147483647
示例1
输入:
10
返回值:
2
说明:
十进制中10的32位二进制表示为0000 0000 0000 0000 0000 0000 0000 1010,其中有两个1。
示例2
输入:
-1
返回值:
32

说明:
负数使用补码表示 ,-1的32位二进制表示为1111 1111 1111 1111 1111 1111 1111 1111,其中32个1
关联企业

class Solution {
public:
     int NumberOf1(int n) {
         int count = 0;
         while (n != 0) {
             //一个整数和这个整数减去1做与运算,等价于把这个整数最右边一个1变成0
             n = n & (n - 1);
             count++;
         }
         return count;
     }
};

如果一个整数不为0,那么这个整数至少有一位是1。
如果我们把这个整数减1:
(1)原来处在整数最右边的1就会变为0,
(2)原来在1后面的所有的0都会变成1(如果最右边的1后面还有0的话)。

举个例子:
一个二进制数1100,从右边数起第三位是处于最右边的一个1。
减去1后,第三位变成0,它后面的两位0变成了1,而前面的1保持不变,
因此得到的结果是1011

我们发现:减1的结果是把最右边的一个1开始的所有位都取反了。

这个时候如果我们再把原来的整数和减去1之后的结果做与运算,
从原来整数最右边一个1那一位开始所有位都会变成0。如1100&1011=1000

一个整数和这个整数减去1做与运算,等价于把这个整数最右边一个1变成0
那么一个整数的二进制有多少个1,就可以进行多少次这样的操作。
11110000
11100000 1次
11000000 2次
10000000 3次
00000000 4次

JZ65 不用加减乘除做加法
简单 通过率:45.77% 时间限制:1秒 空间限制:64M
知识点基础数学
描述
写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号。

数据范围:两个数都满足 −10≤n≤1000
进阶:空间复杂度 O(1),时间复杂度 O(1)
示例1
输入:
1,2
返回值:
3
示例2
输入:
0,0
返回值:
0

位运算:
(1)与运算 a & b 都为1才为1
(2)或运算 a | b 至少有一个为1才为1
(3)异或运算 a ^ b 不同为1

三步走的方式计算二进制值相加:
5-101
7-111

第一步:各位相加的和,得到010,二进制各位相加相当于各位做异或操作,101^111。

第二步:进位相加的和,得到1010,二进制进位相加相当于各位做与操作,再向左移一位,(101&111)<<1。

第三步:重复上述两步, 各位相加 010^1010=1000,进位相加 (010&1010)<<1 = 100。

继续重复上述两步:各位相加 1000^100 = 1100, 进位相加 (1000&100)<<1 = 0

由于进位相加为0,跳出循环,1100为最终结果。

class Solution {
public:
  int Add(int num1, int num2) {
        while (num2 != 0) {
            int temp = num1 ^ num2;
            num2 = (num1 & num2) << 1;
            num1 = temp;
        }
        return num1;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值