//参考derrantcm的博客,网址:https://blog.csdn.net/DERRANTCM/article/details/47052683
package algorithm;
/*
*https://blog.csdn.net/DERRANTCM/article/details/47052683
* 2个整数相除,不使用除法,乘法,取余
原题
Divide two integers without using multiplication, division and mod operator.
If it is overflow, return MAX_INT.
注:multiplication 乘、相乘、增加
division 分开,分割,除法
mod取余
divisor除数
题目大意
不使用除法,乘法和取余,求两个整数的相除的结果,如果有溢出就返回最大的整数。
解题思路
任何一个整数可以表示成以2的幂为底的一组基的线性组合,即num=a_0*2^0+a_1*2^1+a_2*2^2+…+a_n*2^n。基于以上这个公式以及左移一位相当于乘以2,我们先让除数左移直到大于被除数之前得到一个最大的基。然后接下来我们每次尝试减去这个基,如果可以则结果增加加2^k,然后基继续右移迭代,直到基为0为止。因为这个方法的迭代次数是按2的幂知道超过结果,所以时间复杂度为O(log(n))。
具体理解:如 a/b=q a为被除数,b为除数 ,q为商
找出n,此时2^n*b<=a<=2^(n+1)*b, 此时商q=0+2^n,
继续a=a-2^n,如果此时 a>2^(n-1)*b,则q=q+2^(n-1),一直到n=0.
例子:100/9=11
a=100,b=9
2^3 *9 <a=100<2^4*9,此时n=3,n最大为3
则商q=0+2^3=8, 100/9=(2^3 *9+28)/9=2^3+28/9=8+28/9
此时a=28 < 2^2*9=36 ,此时n=3-1=2
此时a=28 > 2^1*9=18 ,此时q=8+2^1=10, a=28-18=10
此时a=10 > 2^0*9=9 ,此时n=0 ,q=10+2^0=11 ,a=10-9=1
* */
public class TwoIntegerDivision {
//dividend为被除数;divisor为除数;
public static int getDivision(int dividend,int divisor){
int min=Integer.MIN_VALUE;//-2147483648
int max=Integer.MAX_VALUE; //2147483647
//System.out.println(min+" "+max);
if(divisor==0||dividend==min&&divisor==-1){
return max;
}
//判断符合 异或(^)
int sign=((dividend<0)^(divisor<0))?-1:1; //异或
//被除数,为防止溢出,求绝对值
long dvd=Math.abs(dividend);
//除数 求绝对值
long dvs=Math.abs(divisor);
//遍历被除数>=除数,直到被除数<除数为止
int result=0;
while(dvd>=dvs){
//记录除数
long tmp=dvs;
long mul=1; //记录商,即此时的n
while(dvd>=(tmp<<1)){
tmp=tmp<<1;// 等价于 divisor<<=1;
mul<<=1; //等价于 result=result<<1
}
System.out.println(mul+" "+tmp);//此时为2^n
//除数减去
dvd=dvd-tmp;
result=(int) (result+mul);
}
return result*sign;
}
public static void main(String[] args) {
//int test=16;
//System.out.println(test+"左移4位="+(test<<4));
//int test1=1;
//System.out.println(test1+"左移4位="+(test1<<=4)+" test1="+test1);
int dvd=100;
int dvs=9;
int result=getDivision(dvd,dvs);
System.out.println("算法求解为:"+result+" 直接相除为="+dvd/dvs);
}
}