java的二进制一些操作

  1. 判断一个数是否是偶数
	/**
	 * 如果把 n 以二进制的形式展示的话,其实我们只需要判断最后一个二进制位是 1 还是 0 就行了,
	 * 如果是 1 的话,代表是奇数,如果是 0 则代表是偶数,
	 * 所以采用位运算的方式的话,如下
	 * @param n
	 * @return
	 */
	private static boolean isOddNumber(int n) {
		return (n & 1) == 1; 
	}

2.交换两个数
不允许你使用额外的辅助变量来完成交换呢

	/**
	 * 三个都是 x ^ y,就莫名交换成功了。在此我解释下吧,我们知道,
	 * 两个相同的数异或之后结果会等于 0,
	 * 即 n ^ n = 0。并且任何数与 0 异或等于它本身,即 n ^ 0 = n。所以,解释如下:

	把(1)中的 x 带入 (2)中的 x,有

	y = x^y = (x^y)^y = x^(y^y) = x^0 = x。 x 的值成功赋给了 y。

	对于(3),推导如下:

	x = x^y = (x^y)^x = (x^x)^y = 0^y = y。
	
	异或运算支持运算的交换律和结合律
	 */
	private static void exchange() {
		int x = 10;
		int y = 20;
		System.out.println("before exchange: ");
		System.out.println("x = "+x+", y = "+ y);
		
		x = x ^ y;
		y = x ^ y;
		x = x ^ y;
		
		System.out.println("after exchange: ");
		System.out.println("x = "+x+", y = "+ y);
	}
  1. 给你一组整型数据,
    这些数据中,其中有一个数只出现了一次,其他的数都出现了两次,
    让你来找出一个数 。
	/**
	 * 我们刚才说过,两个相同的数异或的结果是 0,一个数和 0 异或的结果是它本身,所以我们把这一组整型全部异或一下,
	 * 例如这组数据是:1,  2,  3,  4,  5,  1,  2,  3,  4。其中 5 只出现了一次,
	 * 其他都出现了两次,把他们全部异或一下,结果如下:

	由于异或支持交换律和结合律,所以:

	1^2^3^4^5^1^2^3^4 = (1^1)^(2^2)^(3^3)^(4^4)^5= 0^0^0^0^5 = 5。

	也就是说,那些出现了两次的数异或之后会变成0,那个出现一次的数,和 0 异或之后就等于它本身
	 * @param arr
	 * @return
	 */
	private static int find(int[] arr) {
		int temp = arr[0];
		for (int i = 1; i < arr.length; i++) {
			temp = temp ^ arr[i];
		}
		return temp;
	}

4.m的n次方

	/**
	 * 计算 m 的 n 次方
	 * 我举个例子吧,例如 n = 13,则 n 的二进制表示为 1101, 
	 * 那么 m 的 13 次方可以拆解为:

	m^1101 = m^0001 * m^0100 * m^1000。

	我们可以通过 & 1和 >>1 来逐位读取 1101,为1时将该位代表的乘数累乘到最终结果。
	时间复杂度近为 O(logn),而且看起来很牛逼。
	 * @param m
	 * @param n
	 * @return
	 */
	private static int pow(int m, int n) {
		int sum = 1;
		int tmp = m;
		while(n != 0) {
			if((n & 1) == 1) {
				sum *= tmp;
			}
			tmp *= tmp;
			n = n >> 1;
		}
		return sum;
	}

5.找出不大于N的最大的2的幂指数

	/**
	 * 找出不大于N的最大的2的幂指数
	 * 例如 N = 19,那么转换成二进制就是 00010011
	 * (这里为了方便,我采用8位的二进制来表示)。那么我们要找的数就是,
	 * 把二进制中最左边的 1 保留,后面的 1 全部变为 0。即我们的目标数是 00010000。
	 * 那么如何获得这个数呢?相应解法如下:
	 * 
		1、找到最左边的 1,然后把它右边的所有 0 变成 1
		2、把得到的数值加 1,可以得到 
			00100000即 00011111 + 1 = 00100000。
		3、把 得到的 00100000 向右移动一位,
			即可得到 00010000,即 00100000 >> 1 = 00010000。

		那么问题来了,第一步中把最左边 1 中后面的 0 转化为 1 该怎么弄呢?我先给出代码再解释吧。
		下面这段代码就可以把最左边 1 中后面的 0 全部转化为 1,
			n |= n >> 1;
			n |= n >> 2;
			n |= n >> 4;
			
		就是通过把 n 右移并且做或运算即可得到。我解释下吧,
		我们假设最左边的 1 处于二进制位中的第 k 位(从左往右数),
		那么把 n 右移一位之后,那么得到的结果中第 k+1 位也必定为 1,
		然后把 n 与右移后的结果做或运算,那么得到的结果中第 k 和 第 k + 1 位必定是 1;
		同样的道理,再次把 n 右移两位,那么得到的结果中第 k+2和第 k+3 位必定是 1,
		然后再次做或运算,那么就能得到第 k, k+1, k+2, k+3 都是 1,如此往复下去….
		这种做法的时间复杂度近似 O(1),重点是,高逼格。
	 * @param n
	 * @return
	 */
	private static int findN(int n) {
		n |= n >> 1;
		n |= n >> 2;
		n |= n >> 4;
		n |= n >> 8; // 整型一般是 32 位,上面我是假设 8 位
		// 这种方式有可能导致溢出
		// return (n + 1) >> 1;
		// 下面这种方式可以避免溢出的风险
		return n - (n >>> 1);
	}

6.判断一个数是否是2的N次方

public static boolean is2ToTheNthPower(int value) {
		// 如果输入的数字是2的N次方会等于0
		// 举个例子 8:
		// 8的二进制数:   0000 1000
		// 8-1 的二进制数: 0000 0111
		//                  &
		// 8 & (8-1) =    0000 0000
		return (value & (value - 1)) == 0;
	}

7.获取最右边的1

public static int getRightOne(int value) {
        // 提取出最右边的1
        int rightOne = value& (~value+ 1);
        // 假设 value : 0010 1000
        // 取反 value : 1101 0111
        //  加1                 1
        //              1101 1000
        //     & value: 0010 1000
        //              0000 1000  得到最右的1的值
        return rightOne;
	}

8.arr中,有两种数 a 和 b 出现奇数次 , 其他数均出现偶数次 ,找出出现奇数次的两个数 a 和 b 是多少?

   public static void printOddTimesNum2(int[] arr) {
       int eor = 0;
       for (int i = 0; i < arr.length; i++) {
           eor ^= arr[i];
       }
       // eor = a ^ b
       // eor != 0
       // eor 必有一个位置是1
       // 提取出最右边的1
       int rightOne = eor & (~eor + 1);
       int onlyOne = 0;
       // a 和 b 中必有其中一个数与 rightOne 在同一个位置上是1 ,以此区分出数组中的 a 与 b
       for (int i = 0; i < arr.length; i++) {
           if ((arr[i] & rightOne) != 0) {
               onlyOne ^= arr[i];
           }
       }
       // onlyOne 必定是 a 和 b 其中一个
       // eor = a ^ b
       System.out.println("a 和 b 分别是:  "+onlyOne + " : "+(eor ^ onlyOne));
   }

9.统计1的个数

  public static int bitOneCounts(int N) {
      int count = 0;
      while (N != 0) {
          count ++;
          int rightOne = N & (~N + 1);
          N ^= rightOne;
          // 为什么不用  N -= rightOne , 如果保证N是正数可以 ,N 是负数的话就不行了, 异或最好

          // 使用这种方法可以直接消除最右边的1
          // N &= (N - 1);
      }
      return count;
  }

测试代码:

	public static void main(String[] args) {
		// 1.
		int n = 3;
		if(isOddNumber(n)) {
			System.out.println(n + " 是奇数");
		}else {
			System.out.println(n+" 不是奇数");
		}
		
		// 2.交换两个数
		// 不允许你使用额外的辅助变量来完成交换呢
		exchange();
		
		// 3. 给你一组整型数据,
		// 这些数据中,其中有一个数只出现了一次,其他的数都出现了两次,
		// 让你来找出一个数 。
		int[] arr = new int[] {1, 2,3,4, 5,1, 2,3,4};
		int result = find(arr);
		System.out.println("只出现一次的数: "+result);
		
		
		// 4.m的n次方
		result = pow(2,13);
		System.out.println("2 的 13 次方是: "+result);
		
		// 5.找出不大于N的最大的2的幂指数
		int N = 19;
		result = findN(N);
		System.out.println("找出不大于19的最大的2的幂指数: "+result);

		// 6.判断一个数是否是2的N次方
		int input = 1024;
		boolean b = is2ToTheNthPower(input);
		String str = b?"是":"不是";
		System.out.println("数字 "+ input +" " +str+" 2的N次方");
	}

此编并非原创,只是当初在论坛上看某个大佬的文章,但是找不到链接了,所以使用了原创这个标签

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Java是一种高级编程语言,具有广泛的应用领域。二进制是一种计算机数据的表示方式,它由0和1组成,常用于存储和传输数据。压缩是一种通过降低数据的体积来节省存储空间和传输带宽的技术。而zlib是一个在Java中用于数据压缩和解压缩的开源库。 使用Java进行二进制压缩可以借助zlib这个开源库。zlib提供了一系列的API,可以用于将数据压缩为zlib格式或解压缩zlib格式的数据。 在使用Java进行二进制压缩之前,需要先导入zlib库并确保其正确配置。然后,可以使用Java提供的输入输出流类(如InputStream和OutputStream)来读取和写入数据。 首先,需要创建一个输入流来读取待压缩的二进制数据。可以使用Java提供的FileInputStream类来读取文件,或者使用ByteArrayInputStream类来读取内存中的数据。 接下来,需要创建一个输出流来写入压缩后的数据。可以使用Java提供的FileOutputStream类来写入到文件,或者使用ByteArrayOutputStream类来写入到内存中。 然后,创建一个zlib压缩实例。可以使用Java提供的Deflater类来进行压缩操作,通过调用其相关方法设置参数,然后使用其方法进行实际的压缩。 将读取到的二进制数据传递给Deflater类的方法,进行压缩操作,并将压缩后的数据写入到输出流中。 压缩完成后,关闭输入流和输出流,并进行必要的资源释放。 在需要解压缩的时候,可以使用Java提供的Inflater类来进行解压缩操作,实现与上述类似的步骤。 总之,使用Java进行二进制压缩可以借助zlib库来实现,通过合理使用相关的类和方法,可以轻松地对二进制数据进行压缩和解压缩,从而节省存储空间和传输带宽。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值