给定两个整数,被除数 dividend 和除数 divisor。将两数相除,要求不使用乘法、除法和 mod 运算符。
返回被除数 dividend 除以除数 divisor 得到的商。
示例 1:
输入: dividend = 10, divisor = 3
输出: 3
示例 2:
输入: dividend = 7, divisor = -3
输出: -2
说明:
被除数和除数均为 32 位有符号整数。
除数不为 0。
假设我们的环境只能存储 32 位有符号整数,其数值范围是 [$2^31$, $2^31 − 1$]。本题中,如果除法结果溢出,则返回 $2^31 − 1$。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/divide-two-integers
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
完整代码
基本思想
- 这道题可以用减法的形式去实现,统计被除数中除数的个数,前提是这两个数都要转化成正数
- 难点:越界的情况如何处理???
我要哭了,看来我要好好研究研究,开展个越界专题了
下面的代码测试的时候结果正确,提交后超时
class Solution {
public:
int divide(int dividend, int divisor) {
int res=0;
bool flag=false;
if(dividend==0||divisor==0)
return 0;
if(divisor==1)
return dividend;
if(dividend==INT_MIN&&divisor==INT_MIN){
return 1;
}
else if(dividend==INT_MIN){//被除数是INT_MIN时
if(divisor>0){
flag=true;
dividend=INT_MAX-divisor+1;
res=1;
}
else{
divisor=-divisor;
dividend=INT_MAX-divisor+1;
res=1;
}
}
else if(divisor==INT_MIN){//除数是INT_MIN时
return 0;
}
else{
if(dividend>0&&divisor<0){
flag=true;
divisor=-divisor;
}
else if(dividend<0&&divisor>0){
flag=true;
dividend=-dividend;
}
else if(dividend<0&&divisor<0){
divisor=-divisor;
dividend=-dividend;
}
}
while(dividend>=divisor){
++res;
dividend-=divisor;
if(res==INT_MAX){//结果是正数时,直接返回res即可
if(flag==false)
break;
else{//结果是负数时,只有当二者相等时,结果是INT_MIN,似乎也没有等于INT_MIN的情况了
if(dividend==divisor)
return INT_MIN;
else
break;
}
}
}
return (flag==true)? -res:res;
}
};
好了,参考了人家的思想,自己的疑问一点一点解决
- 越界如何处理?
其实也就是除数为1,或者-1,会出现越界,单独讨论就可以。
定义成比传入的参数更大的数据类型,例如:long
参考人家的第一种思想:递归
首先来说明下,对于两个正数而言,如何不用乘除取余运算来计算两个数相除:规定被除数用a表示,除数用b表示,商用res表示,且a,b都大于0。
利用递归的思想,借助减法来实现。
(之前是统计被除数a中有多少个除数b,借助循环每次都减去一个除数b,统计能减多少次。这种思路并不是不可以,但是,结果是多少就要循环多少次,对于结果是INT_MAX,要循环INT_MAX次,提交结果只通过了几个就超时了。)
其实,可以在上述思想上,进行优化,将除数进行倍增。初始时,如果a<b,结果就是0;下面考虑a>=b的情况,商res初始化为1,如果a>=b+b,那相应的res也将变成res=res+res,直到a<b时,被除数变成a-b,继续上述运算,直到a<b。
class Solution {
public:
int divide(int dividend, int divisor) {
long res=0;
int flag=1;
if(dividend==0||divisor==0)
return 0;
if((dividend>0&&divisor<0)||(dividend<0&&divisor>0))
flag=-1;
long a=dividend;
long b=divisor;
a=(a>0)?a:-a;
b=(b>0)?b:-b;
res=div(a,b);
if(res>INT_MAX){
if(flag==1)
return INT_MAX;
else{
return INT_MIN;
}
}
return (flag==-1)?-res:res;
}
private:
long div(long a,long b){
if(a<b)
return 0;
long res=1,b1=b;
while(b+b<=a){
res+=res;
b+=b;
}
return res+div(a-b,b1);
}
};
执行结果:通过
显示详情
执行用时 :0 ms, 在所有 C++ 提交中击败了100.00%的用户
内存消耗 :8.2 MB, 在所有 C++ 提交中击败了79.14%的用户
移位思想
这题也太难了,代码我都背下来了,但是也很难说清解题思想
尝试着来解释下:
基本思想:
目标:求x
参考:leetcode
class Solution {
public:
int divide(int dividend, int divisor) {
//用移位的方法来处理,没太看明白,先尝试着写一下
if(dividend==0)//被除数为0,结果为0
return 0;
if(dividend==divisor)//被除数等于除数,结果为1
return 1;
//下面的判断是为了排除INT_MIN转化为正数越界的情况
if(divisor==INT_MIN)//除数是INT_MIN,由于所有的数(只看绝对值,这里已经排除了等于的情况)都比INT_MIN的绝对值小,结果为0
return 0;
int add=0;
if(dividend==INT_MIN){
if(divisor==-1)
return INT_MAX;
if(divisor==1)
return INT_MIN;
dividend+=(divisor>0)?divisor:-divisor;//这种情况结果要特殊处理
add=1;
}
//将负数转化为正数
bool flag=false;
if((dividend>0&&divisor<0)||(dividend<0&&divisor>0))
flag=true;
dividend=(dividend>0)?dividend:-dividend;
divisor=(divisor>0)?divisor:-divisor;
//下面开始求商
//思想:求10/2的商,10=2x5(二进制:101)
int res=0;
for(int i=31;i>=0;--i){
int temp=dividend>>i;
res=(res<<1)+(temp>=divisor);
if(temp>=divisor)
dividend-=divisor<<i;
}
res+=add;
return (flag==true)? -res:res;
}
};
执行结果:通过
显示详情
执行用时 :4 ms, 在所有 C++ 提交中击败了84.95%的用户
内存消耗 :8.2 MB, 在所有 C++ 提交中击败了80.77%的用户