位运算相关题目

位运算相关题目

题目1 判断一个整数是不是2的幂

  • 测试链接 : https://leetcode.cn/problems/power-of-two/

  • 思路

    • 2的幂形式为: 0001 0010 0100 1000 … 在每一位上只有一个1
    • n>0时,用Brian Kernighan算法提取出n的最右侧的1, 若提取后的数与原数相等, 则n为2的幂
  • 代码

    • public class Code01_PowerOfTwo {
      
      	public static boolean isPowerOfTwo(int n) {
      		return n > 0 && n == (n & -n);
      	}
      
      }
      

题目2 判断一个整数是不是3的幂

  • 测试链接 : https://leetcode.cn/problems/power-of-three/

  • 思路

    • 幂 > 0
    • 若一个数为3的幂, 则它一定只有3这个质数因子
    • int范围内最大的3的幂(7只含有3这个质数因子)%n,
      • == 0(可以整除) : n为3的幂
      • != 0(不能整除) : n不为3的幂
  • 代码

    • 	public static boolean isPowerOfThree(int n) {
              // 1162261467是int型范围内,最大的3的幂,它是3的19次方
      		return n > 0 && 1162261467 % n == 0;
      	}
      

题目3 返回大于等于n的最小的2的幂

  • 思路

    • 若n <= 0, 则为1
    • 若n > 0
      • 先将n减一, 防止该数就是n的整数倍时, 操作后进位, 返回的不是本身,而是大于本身的数
      • 将减一后的数最左侧的1开始往右全部刷成1
      • n+1 转为2的n次方
  • 代码

    • 	public static final int near2power(int n) {
      		if (n <= 0) {
      			return 1;
      		}
      		n--;// 当n不是2的某次方,没什么影响; 当n是2的某次方,起到降位的作用, 防止返回更大的数而不是本身
      		// 以下代码, 将减一后的数最左侧的1开始往右全部刷成1
      		n |= n >>> 1;
      		n |= n >>> 2;
      		n |= n >>> 4;
      		n |= n >>> 8;
      		n |= n >>> 16;
      		return n + 1;// +1后变成2的某次方
      	}
      

题目4 区间[left, right]内所有数字 & 的结果

  • 测试链接 : https://leetcode.cn/problems/bitwise-and-of-numbers-range/

  • 思路

    • 找规律,发现right &( right - 1) 的结果就是消掉right最右侧的1, 若消掉后的值right’ > left , 说明中间还有值可以继续消掉最右侧的1
    • 一直消1直至right’ < = left, 说明无1可消了, 返回right’
  • 代码

    • 	public static int rangeBitwiseAnd(int left, int right) {
      		while (left < right) {// 用于判断前面到哪里的1能够留下来
      			right -= right & -right;// 每一次和-1后的数相与,都会使结果消掉最右侧的1
      			// 若消掉后的结果> left 说明中间还有数可以继续让最右侧的1消掉
      		}
      		return right;
      	}
      
      

题目5 反转一个二进制的状态,不是0变1、1变0,是逆序。超自然版

  • 测试链接 : https://leetcode.cn/problems/reverse-bits/

  • 思路

    • 运用位运算不断位移拼接,使用二路归并的思想,从局部反转达到整体反转的目的
  • 代码

    • 	public static int reverseBits(int n) {
      		//		1010101010101010			0101010101010101
      		//		保留前一位					保留后一位
      		// 		>>> 1 : 前一位右移			<< 1 : 后一位左移
      		//		|: 将前后的数或到一块, 达到逆转的效果
      		n = ((n & 0xaaaaaaaa) >>> 1) | ((n & 0x55555555) << 1);// 1v1(每两位倒序)
      		n = ((n & 0xcccccccc) >>> 2) | ((n & 0x33333333) << 2);// 2v2(每四位倒序)
      		n = ((n & 0xf0f0f0f0) >>> 4) | ((n & 0x0f0f0f0f) << 4);// 4v4(每8位倒序)
      		n = ((n & 0xff00ff00) >>> 8) | ((n & 0x00ff00ff) << 8);// 8v8(每16倒序)
      		n = (n >>> 16) | (n << 16);// 16v16(每32位倒序)
      		return n;
      	}
      

题目6 返回一个数二进制中有几个1。

  • 测试链接 : https://leetcode.cn/problems/hamming-distance/

  • 思路

    • 二路归并, 每次选相邻两个作为整体, 先计算左侧的1, 再计算右侧的1
    • 两侧的1相加, 自动将两位合并为一个占位为2倍的数
  • 代码

    • // 返回n的二进制中有几个1
      // 两个整数之间的 汉明距离 指的是这两个数字对应二进制位不同的位置的数目。
      // 给你两个整数 x 和 y,计算并返回它们之间的汉明距离
      public class Code06_CountOnesBinarySystem {
      
      	public static int hammingDistance(int x, int y) {
      		return cntOnes(x ^ y);// 统计一下异或后1的个数, 即两个数字对应二进制位不同的位置的数目。
      	}
      
      	public static int cntOnes(int n) {
      		// 1.统计两位中右侧的1		2.统计两位中左侧的1  3.相加 -> 每两位看做一体
      		// 0101 == 5	 0011 == 3 		00001111 == 0x0f0f    
      		// !!!&!!!
       		n = (n & 0x55555555) + ((n >>> 1) & 0x55555555);// 迁移为每2位统计一次1的个数
      		n = (n & 0x33333333) + ((n >>> 2) & 0x33333333);// 迁移为每4位统计一次1的个数
      		n = (n & 0x0f0f0f0f) + ((n >>> 4) & 0x0f0f0f0f);// 迁移为每8位统计一次1的个数
      		n = (n & 0x00ff00ff) + ((n >>> 8) & 0x00ff00ff);// 迁移为每16位统计一次1的个数
      		n = (n & 0x0000ffff) + ((n >>> 16) & 0x0000ffff);// 迁移为每32位统计一次1的个数
      		return n;
      	}
      
      }
      
  • 17
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值