算法们位运算

位运算

注 : 本博客代码全程采用JAVA进行编写

位运算在解决经典算法问题中往往会产生事半工倍的效果,这都要取决于那些神奇的位运算规则,在开始之前,先来看两道经典位运算题目,感受一下位运算的伟大。

1.短路求值原理

题目描述: 计算1+2+3+4+……+n

要求:不准使用乘除法, if while等语句

class Solution{

	public int getResult(int n){
			boolean flag=(n>1) && ((n+=Sum_Solution(n-1))>0);
      return n;
	}
}

2. 不用加减乘除的加法

写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号。

数据范围:两个数都满足 -10 ≤ n ≤ 1000−10≤n≤1000进阶:空间复杂度 O(1)O(1),时间复杂度 O(1)O(1)

解题思路:

//step1:按位与是查看两个数哪些二进制位都为1,这些都是进位位,结果需左移一位,表示进位后的结果
//step2:异或是查看两个数哪些二进制位只有一个为1,这些是非进位位,可以直接加、减,结果表示非进位位进行加操作后的结果
//step3:n1&n2是查看有没有进位位了,如果有,需要重复step1、step2;如果没有,保留n1、n2上二进制为1的部分,用或将之合为一个数,即为最后结果

public class Solution {
    public int Add(int num1,int num2) {
        while(num2!=0){
            int temp=num1^num2;   //拿出不需要进位的
            num2=(num2&num1) << 1;   //将需要进位的往前移动
            num1=temp;
        }
        return num1;
    }
}

上面两道题目都是在leetcode官网摘录的经典题目,如果没看懂也没有关系,接下来一部分会带着你从易到难掌握位运算的常见操作

3. 位运算常见操作

  • 异或 ^:

    • x与0异或为x
    • x与x异或为0
    • 满足交换律 结合律
  • 2的幂 n&(n-1)==0 或者 (n&-n)==n

  • 4的幂 (n&(n-1))==0 && n>0 && n%3==1

  • 3的幂 n>0 && 1162261467 % n==0;

  • 位1的个数

    public class Solution {
        // you need to treat n as an unsigned value
        public int hammingWeight(int n) {
            int count=0;
            while(n!=0){
                count++;
                n=n&(n-1);
            }
            return count;
        }
    }
    
  • 交换数字

    class Solution {
        public int[] swapNumbers(int[] numbers) {
            numbers[0]=numbers[0]^numbers[1];
            numbers[1]=numbers[1]^numbers[0];
            numbers[0]=numbers[0]^numbers[1];
            return numbers;
        }
    }
    

    解释:

    在这里插入图片描述

  • 只出现一次的数字

    class Solution {
        public int singleNumber(int[] nums) {
            int target=0;
            for(int nu:nums){
                target=target^nu;
            }
            return target;
        }
    }
    

    进阶: **只出现一次的数字 II (不会)

  • 汉明距离

    class Solution {
        public int hammingDistance(int x, int y) {
            //1. 相同的位置留0  不同的位置留1
            x=x^y;
            int n=0;
            //2. 计算位置为1的个数
            while(x != 0){
                x=x&(x-1);
                n++;
            }
            return n;
        }
    }
    
  • **找出所有子集的异或总和再求和 (没思路)

    class Solution {
        public int subsetXORSum(int[] nums) {
            int sum=0;
            int i=0,j=0,ans=0;
            for(i=0;i<(1<<nums.length);i++){
                ans=0;
                for(j=0;j<nums.length;j++){
                    if((i & (1<<j)) !=0 ) ans^=nums[j];
                }
                sum+=ans;
            }
            return sum;
        }
    }
    
  • **两整数之和 (好难理解)

    问题转换为这个样子

    在这里插入图片描述

    class Solution {
        public int getSum(int a, int b) {
           // a=a^b;  //不一样的地方为1  a=a&b   //一样的地方为1  左移之后表示进位
            while(b!=0){
                int temp=a^b;   //拿出不需要进位的
                b=(a&b)<<1;
                a=temp;
            }
            return a;
        }
    }
    
    //  递归解决方式 : 更好理解---------
    class Solution {
        public int getSum(int a, int b) {
           return b==0? a: getSum(a^b,(a&b)<<1);
        }
    }
    
  • 插入

    class Solution {
        public int insertBits(int N, int M, int i, int j) {
            for(int p=i;p<=j;p++){
                N &= ~((long) 1<<p);   //每一位都搞成0
            }
            return N | (M << i);
        }
    }
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值