颠倒二进制位(字符串,位操作,分治 Java)

问题

给你一个int,把他的二进制完全倒换过来,然后再输入int

问题参考:190. 颠倒二进制位

方案

1. 字符串操作:很容易想到,操作字符串跟直观

2. 字符数组操作,都可以使用位操作来替代,比如获取哪一位(& 0000 0010), 将结果累加上 (0 | 0010 ),或者增量(0000 0010 << 1, 就可以获取第三位)

3. 读取原始int值二进制最后一位,挨个放在result结果的最高位

4. 读取原始int值二进制最后一位,挨个放在result的最后一位,放之前全部享有移动一个位

5. 字符串跌倒还有种分支算法,即前后字符串跌倒。类似二进制也可以。

1.字符串操作

其中用到技术点

1. 交互char数值,可以参考:位运算.异或概念,性质,应用(交换数值,序列只有一个数重复,序列只有一个不重复)_要钱也要自我实现-CSDN博客

2. 获取int类型的二进制字符串:Integer.toBinaryString(n) 

3. 将二进制转换为int:(int) Long.parseLong(binary,2)。其中Integer.valueOf("10111111111111111111111111111111",2)首字母为1的会解析报错,就使用了long解析函数

		/**
		 * 1.字符串操作
		 * @param n
		 * @return
		 */
		public int reverseBits1(int n) {

			String binary = String.format("%32s", Integer.toBinaryString(n)).replaceAll(" ", "0");
			char[] chars = binary.toCharArray();

			for(int i = 0,j=chars.length-1 ;i<j;i++,j--){
				// 交互
				chars[i] = (char) (chars[i] ^ chars[j]);
				chars[j] = (char) (chars[i] ^ chars[j]);
				chars[i] = (char) (chars[i] ^ chars[j]);
			}
			binary = new String(chars);
			/**
			 * 32个二进制位
			 * Integer.valueOf("10111111111111111111111111111111",2)
			 * 首字母为1的会解析报错
			 */
			return  (int) Long.parseLong(binary,2);
		}

 2.位操作:始终读取int最后一位,从高位到低位挨个放

将二进制按照字符串存储,很浪费内存。

截取最后一位,然后移动到对应位置,跟result(init=0)或

图示

 

 代码

		/**
		 * 2.位操作:始终读取int最后一位,从高位到低位挨个放
		 * - 将二进制按照字符串存储,很浪费内存。
		 * - 截取最后一位,然后移动到对应位置,跟result(init=0)或
		 * @param n
		 * @return
		 */
		public int reverseBits2(int n) {
			// 结果变量 每次出来的二进制位“拼接”进去
			int result = 0;
			// int的二进制位数
			int len = 31; 
			// 中间变量存储
			int temp = 0;
			while(len >= 0 && n != 0){
				// 获取最后一位
				temp = n & 1;
				// 向左移动
				temp = temp << (len--);
				// 拼接到结果上
				result = result | temp;
				// 去掉最后一位
				n = n >>> 1;
			}
			return result;
		}

3.位操作变种:始终读取int最后一位,每次放在第一位

图示

 代码

		/**
		 * 3.位操作变种
		 * - 第二种是将最后1位 左移到指定位置,这种是 每次只将结果左移一位,用来放截取的最后一位
		 * @param n
		 * @return
		 */
		public int reverseBits3(int n) {
			// 结果变量 每次出来的二进制位“拼接”进去
			int result = 0;
			// int的二进制位数
			int len = 31; 
			// 中间变量存储
			int temp = 0;
			while(len >= 0){
				// 获取最后一位
				temp = n & 1;
				// 向左移动一位
				result = result << 1;
				// 拼接到结果最后一位上
				result = result | temp;
				// 去掉最后一位
				n = n >>> 1;
				// 递减
				len --;
			}
			return result;
		}

4.分治+位操作

- 对比第二种和第三种 遍历次数基本是32次
- 改善:一位一位操作太麻烦,能否一次操作几个二进制位。
加上分治算法思想,AB字符串反过来就是BA,如果A或者B也是字符串,前后颠倒就行,好在这里32是2的4次方,固定的,不需要迭代,可以直接写死。

图示

 代码

1. 如果是字符串这么搞,是从:前16和后16位换,前16的前8位和16的后8位换,以此类推;
2. 二进制也可以这么搞,但会出现很多中间变量
3. 优化结果是:从下往上,奇偶互换,两位两位互换,四位四位互换,…… ,前16位和后边16位互换

		public int reverseBits(int n) {

			final int M1 = 0x55555555; // 01010101010101010101010101010101
			final int M2 = 0x33333333; // 00110011001100110011001100110011
			final int M4 = 0x0f0f0f0f; // 00001111000011110000111100001111
			final int M8 = 0x00ff00ff; // 00000000111111110000000011111111
			final int M16 = 0x0000ffff; // 00000000000000001111111111111111

			/**
			 * n >>> 1 & M1
			 * n >>> 1: 偶数位 移动 奇数位
			 * n >>> 1 & M1 : 提取奇数位
			 * 
			 * (n & M1) << 1
			 * n & M1: 提取奇数位
			 * (n & M1) << 1:奇数位 移动到偶数位
			 * 
			 * n >>> 1 & M1 | (n & M1) << 1
			 * 奇偶互换
			 */
			n = n >>> 1 & M1 | (n & M1) << 1;
			
			
			/**
			 * 同理:32位,两两一组,类似奇偶互换一样
			 * 四个四个一组
			 * 八个八个一组
			 */
			n = n >>> 2 & M2 | (n & M2) << 2;
			n = n >>> 4 & M4 | (n & M4) << 4;
			n = n >>> 8 & M8 | (n & M8) << 8;
			/**
			 *  前16和后16互换
			 *  n >>> 16 | n << 16
			 */
			return n >>> 16 & M16 | (n & M16) << 16;
		}

总结

1. 对int的二进制操作,逻辑上可以转为二进制char[]处理的,都可以按照位操作实现

2. 对int的二进制操作,优先考虑位操作。相对于char[]的操作,位操作更简单,比如:前16和后16互换n = n >>> 16 | n << 16

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

闲猫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值