位运算--01---两数相除

Posted 高高for 循环

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了位运算--01---两数相除相关的知识,希望对你有一定的参考价值。

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


两数相除

https://leetcode.com/problems/divide-two-integers

题目:

分析:

除法的意义就在于:求a可以由多少个b组成。那么由此我们可得除法的实现:求a能减去多少个b,做减法的次数就是除法的商。

辅助代码:

加 键 乘


	public static int add(int a, int b) 
		int sum = a;
		while (b != 0) 
			sum = a ^ b;
			b = (a & b) << 1;
			a = sum;
		
		return sum;
	

	public static int negNum(int n) 
		return add(~n, 1);
	

	public static int minus(int a, int b) 
		return add(a, negNum(b));
	

	public static int multi(int a, int b) 
		int res = 0;
		while (b != 0) 
			if ((b & 1) != 0) 
				res = add(res, a);
			
			a <<= 1;
			b >>>= 1;
		
		return res;
	

除法逻辑分析

isNeg(int n) 判断一个数是否小于0

public static boolean isNeg(int n) 
		return n < 0;
	

正常相除逻辑 c= a/b

a= 2的K次方 * b + 2的(K-n)次方*b +…

最后c = b * ( 2^k + 2^(k-n)+…)

   public static int div(int a, int b) 
		int x = isNeg(a) ? negNum(a) : a;
		int y = isNeg(b) ? negNum(b) : b;
		int res = 0;
		for (int i = 30; i >= 0; i = minus(i, 1)) 
			if ((x >> i) >= y) 
				res |= (1 << i);
				x = minus(x, y << i);
			
		
		return isNeg(a) ^ isNeg(b) ? negNum(res) : res;
	
  1. isNeg(int n) 先全部转成正数来计算
  2. int是32位,0-31,其中第31位表示符号位,一位一位的去做判断
  3. (x >> i) >= y , x右移去找能大于等于y的,(等同于y左移小于等于x,不过左移,因为符号位的关系,有安全隐患) --------判断K的值是否存在
  4. 找到符合条件的位数,记录下来 用res= res | (1 << i); 2的k次方存在,对应位数记录为1
  5. 然后x减去 y << i
  6. 循环

return isNeg(a) ^ isNeg(b) ? negNum(res) : res;

a != b 可以转换为 a ^ b

怎么解决系统最小值转绝对值

最小负数 相反数 也是最小负数


分析

public static int divide(int a, int b) 
		if (a == Integer.MIN_VALUE && b == Integer.MIN_VALUE) 
			return 1;
		 else if (b == Integer.MIN_VALUE) 
			return 0;
		 else if (a == Integer.MIN_VALUE) 
			if (b == negNum(1)) 
				return Integer.MAX_VALUE;
			 else 
				int c = div(add(a, 1), b);
				return add(c, div(minus(a, multi(c, b)), b));
			
		 else 
			return div(a, b);
		
	

  1. a 和 b都是系统最小值,则返回1
  2. a不是系统最小, b是系统最小值, ,则返回0
  3. a是系统最小值, b不是
  4. a也不是 ,b也不是----可以直接用上述div(int a, int b)方法

a是系统最小值, b不是,分2种情况

         if (b == negNum(1)) 
				return Integer.MAX_VALUE;
			 else 
				int c = div(add(a, 1), b);
				return add(c, div(minus(a, multi(c, b)), b));
			

第一种: 如果a是系统最小值,且b等于-1

计算机底层规定: 系统最小值比系统最大值多1

比如int范围是: -128到127

  1. 按道理等于系统最大值+1,
  2. 因为计算机底层不存在,系统最大值+1
  3. 所以按leetcode规定,返回系统最大值

所以leetcode规定: 系统最小值/-1 =系统最大值

第二种: 如果a是系统最小值,且b不等于-1

那么令a+1去除以b,后面再去补偿

两数相除----总的代码

public class Code03_BitAddMinusMultiDiv 

	public static int add(int a, int b) 
		int sum = a;
		while (b != 0) 
			sum = a ^ b;
			b = (a & b) << 1;
			a = sum;
		
		return sum;
	

	public static int negNum(int n) 
		return add(~n, 1);
	

	public static int minus(int a, int b) 
		return add(a, negNum(b));
	

	public static int multi(int a, int b) 
		int res = 0;
		while (b != 0) 
			if ((b & 1) != 0) 
				res = add(res, a);
			
			a <<= 1;
			b >>>= 1;
		
		return res;
	

	public static boolean isNeg(int n) 
		return n < 0;
	

	public static int div(int a, int b) 
		int x = isNeg(a) ? negNum(a) : a;
		int y = isNeg(b) ? negNum(b) : b;
		int res = 0;
		for (int i = 30; i >= 0; i = minus(i, 1)) 
			if ((x >> i) >= y) 
				res |= (1 << i);
				x = minus(x, y << i);
			
		
		return isNeg(a) ^ isNeg(b) ? negNum(res) : res;
	

	public static int divide(int a, int b) 
		if (a == Integer.MIN_VALUE && b == Integer.MIN_VALUE) 
			return 1;
		 else if (b == Integer.MIN_VALUE) 
			return 0;
		 else if (a == Integer.MIN_VALUE) 
			if (b == negNum(1)) 
				return Integer.MAX_VALUE;
			 else 
				int c = div(add(a, 1), b);
				return add(c, div(minus(a, multi(c, b)), b));
			
		 else 
			return div(a, b);
		
	


以上是关于位运算--01---两数相除的主要内容,如果未能解决你的问题,请参考以下文章

leetcode实战—位运算(两数相除只出现一次的数字重复的DNA序列等)

[leetcode] 29. 两数相除

python.day.01——运算符分类

两数相除,判断小数位是否有限位

Leetcode29. 两数相除

Divide two numbers,两数相除求商,不能用乘法,除法,取模运算