Skip to content

Commit a15e6fa

Browse files
author
wangpeng
committed
feat(MEDIUM): add _29_divide
1 parent a5b1706 commit a15e6fa

File tree

1 file changed

+131
-0
lines changed

1 file changed

+131
-0
lines changed
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
package pp.arithmetic.leetcode;
2+
3+
/**
4+
* Created by wangpeng on 2019-04-15.
5+
* 29. 两数相除
6+
* <p>
7+
* 给定两个整数,被除数 dividend 和除数 divisor。将两数相除,要求不使用乘法、除法和 mod 运算符。
8+
* <p>
9+
* 返回被除数 dividend 除以除数 divisor 得到的商。
10+
* <p>
11+
* 示例 1:
12+
* <p>
13+
* 输入: dividend = 10, divisor = 3
14+
* 输出: 3
15+
* 示例 2:
16+
* <p>
17+
* 输入: dividend = 7, divisor = -3
18+
* 输出: -2
19+
* 说明:
20+
* <p>
21+
* 被除数和除数均为 32 位有符号整数。
22+
* 除数不为 0。
23+
* 假设我们的环境只能存储 32 位有符号整数,其数值范围是 [−2^31, 2^31 − 1]。本题中,如果除法结果溢出,则返回 2^31 − 1。
24+
*
25+
* @see <a href="https://leetcode-cn.com/problems/divide-two-integers/">divide-two-integers</a>
26+
*/
27+
public class _29_divide {
28+
29+
public static void main(String[] args) {
30+
_29_divide divide = new _29_divide();
31+
System.out.println(divide.divide2(10, 3));
32+
System.out.println(divide.divide2(7, -3));
33+
System.out.println(divide.divide2(-7, -3));
34+
System.out.println(divide.divide2(-2147483648, -1));
35+
System.out.println(divide.divide2(-2, 2));
36+
System.out.println(divide.divide2(2, 2));
37+
System.out.println(divide.divide2(Integer.MAX_VALUE, 2));
38+
}
39+
40+
/**
41+
* 解法二
42+
* 除法的本质起始是看除数中包含多少个被除数,可以利用乘法或者位移使被除数不断变大,直到大于除数
43+
* 由于题目中不允许使用乘法,所以考虑用位移的方式进行计算 <<1 <==> *2
44+
* 1.divisor << 1,直至 > dividend,得到cnt
45+
* 2.dividend = dividend-divisor<<(cnt-1)
46+
* 3.重复第一步拿到最终结果
47+
* 要注意正负值和边界情况
48+
* 时间复杂度O(logn)
49+
*
50+
* @param dividend
51+
* @param divisor
52+
* @return
53+
*/
54+
public int divide2(int dividend, int divisor) {
55+
if (dividend == 0) return 0;
56+
if (divisor == 1) return dividend;
57+
if (divisor == -1) {
58+
if (dividend == Integer.MIN_VALUE) {
59+
return Integer.MAX_VALUE;
60+
}
61+
if (dividend == Integer.MAX_VALUE) {
62+
return Integer.MIN_VALUE;
63+
}
64+
return -dividend;
65+
}
66+
int ret = 0;
67+
long absDividend = Math.abs((long)dividend);
68+
long absDivisor = Math.abs((long)divisor);
69+
while (absDividend >= absDivisor) {
70+
int cnt = 1;
71+
while ((absDivisor << cnt) <= absDividend)
72+
cnt++;
73+
ret += 1 << (cnt - 1);
74+
absDividend -= absDivisor << (cnt - 1);
75+
}
76+
return ((dividend ^ divisor) < 0) ? -ret : ret;
77+
}
78+
79+
/**
80+
* 解题思路:
81+
* 1、不使用乘法、除法和 mod 运算符,那就只能使用加减法了
82+
* 2、for循环不断相减得到结果
83+
* 要注意正负值和边界情况
84+
* <p>
85+
* 此种解法,对于超级大的dividend和超级小的divisor的话,耗时会很长=>O(n)
86+
* 见解法二 {@link _29_divide#divide2(int, int)}
87+
*
88+
* @param dividend
89+
* @param divisor
90+
* @return
91+
*/
92+
public int divide(int dividend, int divisor) {
93+
if (divisor == 1) {
94+
return dividend;
95+
}
96+
if (divisor == -1) {
97+
if (dividend == Integer.MIN_VALUE) {
98+
return Integer.MAX_VALUE;
99+
}
100+
if (dividend == Integer.MAX_VALUE) {
101+
return Integer.MIN_VALUE;
102+
}
103+
return -dividend;
104+
}
105+
106+
int ret = 0;
107+
//异或
108+
int xor = dividend ^ divisor;
109+
if (xor == 0) {
110+
return 1;
111+
} else if (xor > 0) {
112+
//相同运算符
113+
while ((dividend ^ divisor) > 0) {
114+
dividend -= divisor;
115+
if ((dividend ^ divisor) >= 0 || dividend == 0) {
116+
ret++;
117+
}
118+
}
119+
} else {
120+
//不同运算符
121+
while ((dividend ^ divisor) < 0) {
122+
dividend += divisor;
123+
if ((dividend ^ divisor) <= 0 || dividend == 0) {
124+
ret--;
125+
}
126+
}
127+
}
128+
129+
return ret;
130+
}
131+
}

0 commit comments

Comments
 (0)