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
提示:
被除数和除数均为 32 位有符号整数。
除数不为 0。
假设我们的环境只能存储 32 位有符号整数,其数值范围是 [−231, 231 − 1]。本题中,如果除法结果溢出,则返回 231 − 1。
l为什么从1而不是0开始,//l=0的话第一次就存在溢出:(r-l+1)>>1
class Solution {
public int divide(int dividend, int divisor) {
if(dividend==Integer.MIN_VALUE){
if(divisor==1)return Integer.MIN_VALUE;
if(divisor==-1)return Integer.MAX_VALUE;
}
if(divisor==0)return 0;
int fu=1;
if(dividend>0){
dividend=-dividend;
fu*=-1;
}
if(divisor>0){
fu*=-1;
divisor=-divisor;
}
int l=1,r=Integer.MAX_VALUE;
while(l<r){
int mid=l+((r-l+1)>>1);//l=0的话第一次就存在溢出
if(mid==Integer.MAX_VALUE)return Integer.MAX_VALUE;//中间值可能到边界
boolean check=qadd(divisor,mid,dividend);
if(check)l=mid;
else r=mid-1;
}
if(qadd(divisor,l,dividend)==false)l=0;
return fu*l;
}
public boolean qadd(int y,int z,int x){
//要始终保证z*y>=x;返回true
int ad=y;
int ans=0;
while(z>0){
if((z&1)==1){
if(ans<x-ad)return false;
ans+=ad;
}
if(z!=1){//z=1时不用加了,都跳出循环了
//防止ad溢出,同时做判断
if(ad<x-ad)return false;
ad+=ad;
}
z>>=1;
}
return true;
}
}
另一种二分模板
class Solution {
public int divide(int dividend, int divisor) {
if(dividend==Integer.MIN_VALUE){
if(divisor==1)return Integer.MIN_VALUE;
if(divisor==-1)return Integer.MAX_VALUE;
}
int fu=1;
if(dividend>0){
dividend=-dividend;
fu*=-1;
}
if(divisor>0){
fu*=-1;
divisor=-divisor;
}
int l=0,r=Integer.MAX_VALUE,ans=(int)Math.random()*Integer.MAX_VALUE;
while(l<=r){
int mid=l+((r-l)>>1);
if(mid==Integer.MAX_VALUE)return mid;//比上一种模板多了溢出判断,//因为,下面可能需要执行l=mid+1导致溢出,而第一个模板则是l=mid,不存在这种情况
boolean check=qadd(divisor,mid,dividend);
if(check){
ans=mid;
l=mid+1;
}else{
r=mid-1;
}
}
return fu*ans;
}
public boolean qadd(int y,int z,int x){
//要始终保证z*y>=x;返回true
int ad=y;
int ans=0;
while(z>0){
if((z&1)==1){
if(ans<x-ad)return false;
ans+=ad;
}
if(z!=1){//z=1时不用加了,都跳出循环了
//防止ad溢出,同时做判断
if(ad<x-ad)return false;
ad+=ad;
}
z>>=1;
}
return true;
}
}