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); }

浙公网安备 33010602011771号