29_两数相除

题目

给定两个整数,被除数 dividend 和除数 divisor。将两数相除,要求不使用乘法、除法和 mod 运算符。

返回被除数 dividend 除以除数 divisor 得到的商。

整数除法的结果应当截去(truncate)其小数部分,例如:truncate(8.345) = 8 以及 truncate(-2.7335) = -2

边界 : 假设我们的环境只能存储 32 位有符号整数,其数值范围是 [−2的31次方,  2的31次方 − 1]。本题中,如果除法结果溢出,则返回 2的31次方 − 1。

分析题目

  • 不能直接while循环,以减法代替除法,这样会超出时间限制
  • 要注意上下界
  • 下界不能直接取绝对值,因为这样会溢出,但是正数取相反数变负数不会溢出
  • 除数和被除数符号一共有四种组合,我们可以将其分为两大类

代码

先写出所有特殊情况

if(dividend == -divisor ) return -1;
    if(dividend ==divisor) return 1;
    if (dividend == 0) return 0;
    if (divisor == 1) return dividend;
    if (divisor == -1) {
        if (dividend = Math.pow(-2, 31)) return Math.pow(2, 31) - 1;
        else
            return -dividend;
    }

然后确定符号,flag为1代表结果为正,为0则结果为负

let sign = 0;
    if ((dividend > 0 && divisor > 0) || (dividend < 0 && divisor < 0)) {
        sign = 1;
    }
    else
        sign = 0;

因为正数变负数不会溢出,所以我们统一将除数和被除数都变成负数。如果被除数大于除数,直接返回0

 dividend=dividend>0 ? -dividend :dividend;
    // 正变负数,不会溢出
    divisor=divisor>0 ? -divisor :divisor;
    if(dividend>divisor) return 0;

用div函数求出结果,再根据符号正负返回最终结果。

let ans= div(dividend,divisor);
    if(sign==1) 
    {
        if(ans>Math.pow(2,31)-1) return Math.pow(2,31)-1;
      return ans;  
    }
    else {
        if(-ans <Math.pow(-2,31)) return Math.pow(-2,31);
     else return -ans;   
    }

div函数是这个算法最重要的部分。函数思想涉及递归,递归第一步先写终止条件:如果除数和被除数相等则返回1,如果不够商1了,则返回0.

之前说过,如果用减法代替除法,每次减去一个除数大小,则会超时。但如果减去除数的倍数大小则能让复杂度下降,为了方便举例,这里以两个正数为例,

13和3:13比3的翻倍也就是6大,那将3翻倍变6,再将13和6的翻倍也就是12比,13比12大,那将6翻倍变12,再将13和12的翻倍也就是24比较,13比24小,也就是13是位于12和24之间的。

我们将count(这里为4)记下,将余数(这里为13-12=1)作为被除数继续调用div()。

function div(dividend,divisor){
    if(dividend>divisor) return 0; //终止条件
    if(dividend== divisor) return 1; 
    let count =1;
    let disor=divisor;
    while(dividend <disor+disor){ 
        disor=disor+disor;
        count=count+count;
    }
    return count+div(dividend-disor,divisor);
}

 

posted @ 2021-09-21 13:40  李点  阅读(142)  评论(0)    收藏  举报