题目链接
https://leetcode-cn.com/problems/divide-two-integers/
解题思路
思路:让除数来逼近被除数。
按照这个思路,自然就会想要得到两个值,就设为pre,cur,即取值区间为[pre,cur];
然后使用二分查找,不断缩减区间范围,最终找到答案。
这个思路是挺简单的,但是这个题目限制使用乘除法和mod运算符,那么怎么才能逼近被除数呢。
加法。
移位操作。(移位操作应该不算是乘法除法吧¬_¬)
加法比移位慢,当然选移位。
那么问题又来了,被除数和除数的正负号不一致的话,移位就没有效果了,他们只会越来越远~
所以要统一符号,那就统一为负号吧,因为负数的区间比正数的大。
emmm实际操作了下,又有几个很显然的问题:
被除数太大了(指绝对值),比如-2^31,我怎么才能找到比它大的值。(这个题目好像还限制了使用int型(⊙﹏⊙))
除数在左移的时候,一不小心它越界了,就是超出了负数的区间,就会变成正数或0
针对这个问题,我想到的一个方法就是把被除数分一半,即被除数向右移一位,这样就肯定能找出区间了。
但是这个情况下,就要考虑最后的余数和是否大于除数,可能对结果会有1的差别。
这边我解释下为什么只会有1的差别 (我一开始还以为需要把余数的和再来一遍全流程的QAQ)?
1 2 3 4 5 6 7 8 9 10 11
| 设被除数为a,除数为b。
a = a >> 1;
余数 c = a%b, 0<= c < b;
最后的余数和为 d = 2*c + 1 (此处a为奇数,为奇数时d的值能达到最大)
此时 d的最大值为 2**(b-1)+1 = 2**b -1;
2*b-1 /b 的商最大为1,故只会有1的区别。
|
最后,ans = (divident >> 1) /divisor, ans = ans <<1, ans += 余数和部分的商,判断下dividend和divisor的符号是否一致,
一致直接返回ans,不一致返回-ans。
废话
emm代码写到最后的时候,总感觉写的像**一样,逻辑不够清晰,痛苦不能一个享受(~ ̄▽ ̄)~,请君欣赏下这个毒代码,顺便有啥不对的一定要告诉我,感谢你的阅读~
哦,这个代码提交竟然还只要1ms,amazing!
代码
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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
| class Solution {
public int divide(int dividend, int divisor) {
if (divisor == 1) return dividend;
if (dividend == Integer.MIN_VALUE && divisor == -1) return Integer.MAX_VALUE;
if (divisor == -1) return -dividend;
boolean sign = false,odd = false;
if (dividend > 0 && divisor < 0 || dividend < 0 && divisor > 0) sign = true;
dividend = dividend > 0 ? -dividend : dividend;
divisor = divisor > 0 ? -divisor : divisor;
if (divisor < dividend) return 0;
if (divisor == dividend || divisor+divisor < dividend || divisor+divisor > 0) return sign ? -1 : 1;
int temp = -dividend & 1;
if (temp == 1) {
odd = true;
dividend ++;
}
temp = divisor;
int ans,pre = -1,cur = 1;
dividend = dividend >> 1;
while (divisor > dividend) {
pre = cur;
cur = cur << 1;
divisor = divisor << 1;
}
int preValue = divisor >> 1;
int mid,midValue,diff;
while (true) {
if (preValue == dividend || cur-pre == 1) {
ans = pre;
diff = dividend - preValue;
break;
}
if (divisor == dividend) {
ans = cur;
diff = dividend - divisor;
break;
}
mid = pre + ((cur - pre) >> 1);
midValue = preValue + ((divisor-preValue) >> 1);
if (midValue >= dividend) {
pre = mid;
preValue = midValue;
}
else {
cur = mid;
divisor = midValue;
}
}
diff <<= 1;
ans <<= 1;
if (odd) diff--;
if (diff < temp) ans++;
if (sign) return -ans;
return ans;
}
}
|