两数相除
从今天开始学习一下其他大佬,,在自己的小破站上记录一下自己在leetcode上遇到的坑和一些超级大佬的思想。
今天由于是第一次记录刷题的经验(原本我这个小破站是主打各种番剧的,尤其是那种,你懂的(>^ω^<)),可能会有些不足,还望海涵。。。。。
题目介绍
给定两个整数,dividend与divisor,两数相除,不能使用乘法,触法,mod运算,返回商,小数部分向零截断,当除法结果溢出,返回Integer.MAX_VALUE.
我的解法
一开始我自然是按照最基本的方法去做,既然乘法与除法等都不让用,那我加法总可以吧,所以一开始我的做法是这样的:
1 | int ans = 0; |
结果嘛,显而易见的只过了两个测试用例,,到了第三个用例,就直接报了超出时间限制的错(很明显)
接下来,既然超出时间限制,那就加快累加:
1 | int ans = divisor; |
这里我没有完整写出,举个例子:31/3
3+3=6 k=2
6+6=12 k=4
12+12=24 k=8
24+24=48>31
说明最后的结果一定大于等于8,但是大多少,,我当时并没有想出方法,后面看了大神的方法才知道,先暂时不说
最后,我的想法就是递归,,可以我写了好久都没递归出来(对于递归我实在没什么法子,,脑袋太笨)
本题解答思路
最常见的位操作(左移乘2)
思路上就是将除数不断移位,使其逼近被除数,举个例子:31/3
3<<1 = 6
3<<2 = 12
3<<3 = 24
3<<4 = 48 > 31
被除数=被除数-24 = 7
3<<1 = 6
3<<2 = 12 > 7
被除数=被除数-6 = 1
1<3
退出
代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32public int divide(int dividend, int divisor){
//判断符号
int tag = 0; // -1表示负,1表示正
if((dividend>0 && divisor<0) || (dividend<0 && divisor>0)){
tag = -1;
}else if(dividend==0){
return 0;
}else{
tag = 1;
}
//溢出处理
if(dividend==Integer.MIN_VALUE && divisor==-1){
return Integer.MAX_VALUE;
}
long d1 = Math.abs((long) dividend);
long d2 = Math.abs((long) divisor);
int k = 0;
int ans = 31;
//计算结果值
while (ans>=0){
if(d1 < d2<<ans){
ans--;
continue;
}
k += (1<<ans);
d1 -= d2<<ans;
}
return tag * k;
}(注意,上述代码里的左移位数是直接从31开始往下减,这样可以对较大的数逼近的更快)
不知道细心的同学有没有发现啥,没错,移位的思想和我之前的第二种想法很像,只是我是加,它是移位
累加+递归
累加的想法就是我那个,至于递归,看看代码就懂了
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32public int divide(int dividend, int divisor){
if(dividend==Integer.MIN_VALUE && divisor==-1){
return Integer.MAX_VALUE;
}
int tag = 1;
if((dividend<0 && divisor>0) || (dividend>0 && divisor<0)){
tag = -1;
}
//将被除数与除数全部转为负数(负数的范围比正数大)
int a = dividend>0?-dividend:dividend;
int b = divisor>0?-divisor:divisor;
int ans = div(a,b);
if(tag==1){
return ans;
}else{
return -ans;
}
}
private int div(int a,int b){
if(a>b){
return 0; //负数
}
int b1 = b;
int ans = 1;
while(b1 + b1 >= a && b1 + b1 <0){
b1 += b1;
ans += ans;
}
return ans + div(a - b1,b);
}这个代码里最精彩的地方不是递归,不是累加,而是对溢出的处理:
首先,现将被除数与除数全部转化为负数,(原因是在32位有符号整数中,负数的范围比正数大);其次,通过判断b1+b1的符号来判断累加中是否溢出,因为两个负数累加后溢出一定是正数
结束
以上就是我在这道题里学到的东西—对溢出的特殊判断,以及我思路上的断线是在哪断的这个问题