30分钟掌握位运算

目录

位运算符的介绍

位运算妙解

位运算高效解N皇后问题

实际项目中的位运算应用


位运算符的介绍

  • 左移操作<<

将a的二进制表示的每一位向左移动b位,左边超出的位截掉,右边不足的补0.
A=5。A的二进制表示为110.
A<<2= 11000.

  • 右移操作>>和>>>

>>将二进制数按指定右移几位,移掉的省略,左边遗失的位,(该数是正数)用0补齐,(该数是负数)用1补齐。
>>>将二进制按指定右移几位,移掉的省略,左边缺失的位,用0补齐。

  • 按位与操作 A&B

按位与操作 A&B 将A和B的二进制表示的每一位进行与操作,只有两个对应的二进制位都为12时,结果为才返回1,否则返回0.
A=10。二进制:001010 B=44二进制:101100。
A = 001010
B = 101100
A&B =001000

  • 按位或操作 A|B

将A和B的二进制每一位进行或操作,只要两个对应的二进制位有一个为1,结果就为1,否则为0。
A = 001010
B = 101100
A|B=101110

  • 按位异或操作A^B

A和B 的二进制表示的每一位进行异或操作,如果对应的二进制位不同,则结果为1,否则为0.
A = 001010
B = 101100
A^B=100110

  • 按位非操作 ~ A

将A的二进制表示每一位进行取反操作,如果对应的二进制位为0,结果位为1,否则为0.
 A=00001011
~A = 11110100


位运算妙解

  • 数组查非重

  给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
  你的算法应该具有线性复杂度,你可以不使用额外的空间来实现吗?
实例一:
 输入[2,2,1] 输出:1
实例二:
 输入[4,1,2,1,2] 输出:4
题目解析:
  根据题目描述,由于加上了时间复杂度必须是O(n),并且空间复杂度为O(1)的条件,因此不能用排序方法,也不能使用map数据结构。

//两个相同的数异或等于0
public static int funtion(int[] a) {
		for (int i = 1; i < a.length; i++) {           
			a[0]=a[0]^a[i];                   //返回数组中全部元素异或
		}
		return a[0];
	}

  • 数组查非重进阶版
    进阶版 有一个 n 个元素的数组,除了两个数只出现一次外,其余元素都出现两 次,让你找出这两个只出现一次的数分别是几,要求时间复杂度为 O(n) 且再开辟的内存空间固定(与 n 无关) 即O(1)。 示例 :输入: [1,2,2,1,3,4] 输出: [3,4]
    解题思路:数组中全部数字异或得到的应该是两个不同的数直接异或结果。该结果二进制中1的位置的为两不同数不相同的位置。再将该位置以1,0讲数组分为两组,分别求每组全体异或结果,两个结果即为两个不同的数。
public static int[] funtion(int[] a) {
		int[] result= new int[2];
		int res=a[0];
		for (int i = 1; i < a.length; i++) {
			res^=a[i];
		}                                        //全部整数异或结果
		int bitIntex=0;
		for (int i = 0; i < 32; i++) {
			if((res>>i & 1)== 1) {
				bitIntex=i;
				break;
			}
		}										//获取第一个异或结果不为0的位
		for (int i = 0; i < a.length; i++) {
			if ((a[i]>>bitIntex & 1)==1) 
				result[0]^=a[i];
			else 
				result[1]^=a[i];
		}										//根据位分别位1还是0将数组分为两组,分别异或
		return result;
	}

  • 数组查非重再进阶
    题目描述:数组中,只有一个数出现一次,剩下都出现三次,找出出现一次的数
      因为数是出现三次的,也就是说,对于每一个二进制位,如果只出现一次的数在该二进制位为1,那么这个二进制位在全部数字中出现次数无法被3整除。

5   0101       从右边第三位数值(1)加起来
4   0100     后不能被三整除,则单独数在此二
5   0101     进制为上为1,,加起来能被三整除
5   0101     的,单独数在该二进制位为0

public static int findNum(int[] num) {
		int result=0;
		for (int i =0 ; i < 32; i++) {                  //二进制最多32位
			int bit=0;                                 //记录每个数在 二进制第i位 加起来的数值 初始位0
			for (int j = 0; j < num.length; j++) {
				bit+=((num[j]>>i)&1);					//bit 每个数在 i位置的(1)和		
			}
			result |=((bit%3)<<i);                      //result 为每个位置 bit%3 后相按位或
		}
		return result;
	}

  • 2的幂次方
      题目来源于 LeetCode 上第 231 号问题:2 的幂。题目难度为 Easy,目前通过率为 45.6% 。
      题目描述:给定一个整数,编写一个函数来判断它是否为2的幂次方。
    首先,分析一下2的幂次方数的二进制写法
    124816……
    110100100010000……

  仔细观察,可以看出 2 的次方数都只有一个 1 ,剩下的都是 0 。根据这个特点,只需要每次判断最低位是否为 1 ,然后向右移位,最后统计 1 的个数即可判断是否是 2 的次方数。

public static boolean isPowerTwo(int n) {
		int cnt=0;
		while(n>0) {
			cnt+= n&1;
			n>>=1;
		}
		return cnt==1? true:false;
	}

  该题还有一种巧妙的解法。再观察上面的表格,如果一个数是 2 的次方数的话,那么它的二进数必然是最高位为1,其它都为 0 ,那么如果此时我们减 1 的话,则最高位会降一位,其余为 0 的位现在都为变为 1,那么我们把两数相与,就会得到 0。
 1000
& 0111
 ------
 0000

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

  • 4的幂次方
      给定一个整数 (32 位有符号整数),请编写一个函数来判断它是否是 4 的幂次方。(不使用循环或者递归来完成本题)
十进制二进制
210
4100(1在第三位)
81000
1610000(1在第五位)
32100000
641000000(1在第七位)
12810000000
256100000000(1在第九位)

  规律:4的幂次方的数的二进制1的位置都是在奇数位,解题思路:** 先判断该书是否为2的幂,如果是,再在2的幂基础上判断是否为4的幂。判断方法:令该数与特殊数**“1010101010101010101010101010101”** 异或,如果结果是它本身,则该数为4第幂次数。特殊数的16进制写法为0x55555555

public static boolean isPowerOfFour(int num) {
		if(num <=0)
			return false;
		//先判断是不是2的幂
		if((num & num-1)!= 0)
			return false;
		if((num & 0x55555555)==num) {
			return true;
		}
		return false;
		
	}

  • 交换数值大小
      交换两个数相信很多人天天写过,我也相信你每次都会使用一个额外来变量来辅助交换,例如,我们要交换 x 与 y 值,传统代码如下:
int tem=x; 
    x=y; 
    y=tem;

这样写有问题吗?没问题,通俗易懂,万一哪天有人要为难你,不允许你使用额外的辅助变量来完成交换呢?你还别说,有人面试确实被问过,这个时候,位运算就来了。代码如下:

		a=a^b;
		b=a^b;
		a=a^b;

位运算支持交换律,即a^b^a=a^a^b=b.

位运算高效解N皇后

  问题描述: 八皇后问题是一个以国际象棋为背景的问题:如何能够在8×8的国际象棋棋盘上放置八个皇后,使得任何一个皇后都无法直接吃掉其他的皇后?为了达到此目的,任两个皇后都不能处于同一条横行、纵行或斜线上。八皇后问题可以推广为更一般的n皇后摆放问题:这时棋盘的大小变为n×n,而皇后个数也变成n。当且仅当n = 1或n ≥ 4时问题有解。

static int upperlimit;
	static int count;
	public static void main(String[] args) {
		int n=5;
		upperlimit=(1<<n)-1;
		fun(0, 0, 0);
		System.out.println(count);
	}
	static void fun(int row,int ld,int rd) {
		int pos,p;
		if(row!=upperlimit) {
			pos=upperlimit&(~(row|ld|rd));
			while(pos!=0){
				p= (~pos+1) & pos;
				pos-=p;
				fun((row|p), (ld|p)<<1, (rd|p)>>1);
			}
		}else {
		count++;
		}
	}

代码先呈上,若本帖阅读超一千,我会补齐这一块的解释 嘻嘻嘻

实际项目中的位运算应用

一位大佬的博客

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值