leetcode算法-两数相除 前端
题目链接: leetcode-29-两数相除
此题需要在不使用乘法,除法,取模的情况下求的两数相除的结果, 开始看到这道题,以为使用位运算做的,结果发现位运算里面太多的循环,导致并不能通过测试.
首先要知道除法的定义, 除法的定义其实非常简单,比如: 10 / 3 = x => 3x = 10 => x + x + x = 10 所以我们只需要循环执行 +除数 操作,直到和大于或者小于被除数时,就可以得到当前的商。当然使用减法也是可以的。 这就是暴力求解的做法
但是单纯的循环执行 +除数 操作非常耗时,所以需要对步长进行调整,每一次相加如果小于被除数,那么就将步长加一,如果大于被除数了就调整步长为 0 再次重复上述操作,直到相加结果大于被除数,并且步长为0.
比如 16 / 3 第一次 +3, 第二次 +6,第三次 +12 因为第三次的结果已经大于 16 了所以我们需要调整为步长,第四次 +3,第五次 +6 因为第五次又超过了被除数,所以再次调整步长,第六次 +3 第七次 +6 又超过了被除数,再次调整步长 第八次 +3 依旧超过了被除数,并且步长为 0 所以直接返回商.
直接看代码:
export default function divide(dividend: number, divisor: number): number {
// 一系列剪枝操作
// 除数与被除数相等时直接 返回 1
if (dividend === divisor) return 1;
// 除数为 1 时直接返回除数
if (divisor === 1) return dividend;
// 除数为 -1 时,如果被除数为 2^31 那么溢出了,所以直接返回 2^31 - 1,否则就返回被除数取反
if (divisor === -1) {
if (dividend === -2147483648) return 2147483647;
return ~dividend + 1;
}
// *统一两个数的符号
const _dividend = dividend < 0 ? ~dividend + 1 : dividend;
const _divisor = divisor < 0 ? ~divisor + 1 : divisor;
// 除数大于被除数返回 0
if(_divisor > _dividend) return 0;
// 用于存储当前的和
let sum = 0;
// 商
let quotient = 0;
// 步长
let step = 0;
// *注意在 js 中 number 因为包含了浮点数,只剩下了 32 位,然后还有一位符号位,所以整数部分只有 31 位,所以步长不能溢出,这里就是确定最大步长 31 减去当前除数的位数就是最大步长
const stepMax = 31 - _divisor.toString(2).length;
while (1) {
// *首先计算出当前 加数
const tempDivisor = _divisor << step;
// 如果 和 大于被除数
if ((sum + tempDivisor) > _dividend) {
// 如果步长为 0 那么直接返回
if (step === 0) break;
// 否则将步长重置为 0,并且跳过这次循环
step = 0;
continue;
}
// sum 存储和
sum += tempDivisor;
// !quotient 应该存储当前相加的 _divisor 的个数,那么就应该是 (_divisor << step) / _divisor 所以得到 1 << step
quotient += 1 << step;
// *确保 step <= stepMax
step = step < stepMax ? step + 1 : step;
}
// *判断符号 ^ 异或的规则是,0 ^ 0 = 0, 1^1=0, 0^1=1, 1^0=1 相同得0,不同得1 这与正负数之间的操作一样,所以可以用来判断符号
if ((dividend ^ divisor) < 0) return -quotient;
return quotient;
}
测试结果: