这是我参与8月更文挑战的第19天,活动详情查看:8月更文挑战
今天是中国医师节,如果不是因为老婆是医生,朋友圈有很多她同事发的照片,我想我也很难注意到这个不太知名的节日。
医生本来应该是令人尊敬的职业,特别是在处于疫情防控的当下,医生被社会的需要程度是比之前更多的。即使是这样,中国医师节这个节日还是知道的人非常少,引用一段话,希望更多人知道这个节日:
2017年11月3日,国务院通过了卫计委关于“设立中国医师节”的申请,同意自2018年起,将每年的8月19日设立为“中国医师节”。中国医师节是经国务院同意设立的卫生与健康工作者的节日,体现了党和国家对1100多万卫生与健康工作者的关怀和肯定。
说回来,技术方面我们需要继续精进,今天做的是leetcode 第29题。
题目
给定两个整数,被除数 dividend 和除数 divisor。将两数相除,要求不使用乘法、除法和 mod 运算符。
返回被除数 dividend 除以除数 divisor 得到的商。
整数除法的结果应当截去(truncate)其小数部分,例如:truncate(8.345) = 8 以及 truncate(-2.7335) = -2
示例 1:
输入: dividend = 10, divisor = 3
输出: 3
解释: 10/3 = truncate(3.33333..) = truncate(3) = 3
示例 2:
输入: dividend = 7, divisor = -3
输出: -2
解释: 7/-3 = truncate(-2.33333..) = -2
思路
这个题目一看挺简单,但是有意思的是,不让使用乘法、除法和 mod 运算符。
除法不让用,不能直接求的答案。我们就需要想另外的办法来逼近答案,一个重要的线索是,结果是正数,那么我们是可以不断逼近来求的,如果是小数,可以逼近但是可能永远也无法得到最终结果。
乘法不让使用,我们知道可以使用位移来替代 *2 或者 /2 这个操作。
有了上面这些线索,我们可以这么做:
1、先处理掉特殊情况,比如 dividend = 0, divisor = 1, divisor = -1。特别是 divisor = -1的时候,还需要考虑溢出,因为最小的负数是 -2^31, 最大的正数是 2^31-1
2、处理掉特殊情况后,还要处理掉结果的正负号
3、都处理完之后,我们就变成比较简单的 a / b的情况了,a < b,那么返回0,否则,结果大于等于1。如果a >= b + b,那么结果可以 * 2,因为不能用乘法,这个操作可以用上面说的位移操作来代替。b = b * 2,然后继续比较,直到a比b小为止。
有一个注意点是,在计算的过程中,可能超过int的最大值,比如上面说到的 *2 的操作,如果原始数据是 2^30,那么乘以2就会溢出,所以比较简单的处理方式是直接使用long。
Java版本代码
class Solution {
public int divide(int dividend, int divisor) {
if (dividend == 0) {
return 0;
}
if (divisor == 1) {
return dividend;
}
if (divisor == -1) {
// 注意取值范围为 -2^31 ~ 2^31 -1 ,所以当-2^31 / -1 时,结果会溢出
if (dividend == Integer.MIN_VALUE) {
return Integer.MAX_VALUE;
} else {
return -dividend;
}
}
// 判断结果的正负
boolean neg = false;
long dividendLong = dividend;
if (dividend < 0) {
neg = !neg;
dividendLong = 0L - dividend;
}
long divisorLong = divisor;
if (divisor < 0) {
neg = !neg;
divisorLong = 0L - divisor;
}
int ans = divideSimple(dividendLong, divisorLong);
if (neg) {
ans = -ans;
}
return ans;
}
/**
* 简单除法,把各种异常的情况都已经排除,dividend和divisor都是非负整数,而且结果也不会超过限制
* @param dividend
* @param divisor
* @return
*/
private static int divideSimple(long dividend, long divisor) {
if (dividend < divisor) {
return 0;
}
int ans = 1;
long divisorTemp = divisor;
while (dividend >= divisorTemp + divisorTemp) {
ans = ans << 1;
divisorTemp = divisorTemp << 1;
}
return ans + divideSimple(dividend - divisorTemp, divisor);
}
}