[LeetCode29]Divide Two Integers

Divide two integers without using multiplication, division and mod operator.

Analysis:

Note that is the dividend < divisor as they all integer and the return value is also integer, the return value would be 0. (e.g. 3/4=0)

Without using the *, /, and % operator, what we can use is +,-, and <<, >> .
<< 1 is to multiply 2,e.g. 2<<1 = 4;
>> 1 is to divide 2 e.g. 8>>1 = 4;

Originally, the divide operation can use - only, but this is time-consuming, especially when the dividend is large and the divisor is small. e.g. 123456789/1.

So, use << to speed up.
1. Keep multiply 2 (<<1) to the divisor, until it is greater than the dividend. Store the times of shift operation.
2. if dividend > divisor, then dividend = dividend - divisor/2(>>1). Until dividend< original divisor. Store the result.
3. Output the result.

e.g. 13/3

3*2*2*2=24>15,

15 - 24/2 = 3 - 12/2/2=0 < 3, end.
res = 4, res = 4+1, res=5

Another concern is the negative and positive integer and the range of integer. The pos and neg problem can be solved using abs function and the unsigned type cast. The later one we can use the long long type.

In C++ integer type, from small to large:
short (unsigned) 2 Bytes
int (unsigned) 4 Bytes
long (unsigned) 4 Bytes
long long (unsigned) 8 Bytes

in Java, there is no unsigned integer

byte -128~127 1Byte
short -32768~32767 2Bytes
int(-2147483648~2147483647)4Bytes
long(-9223372036854774808~9223372036854774807)8Bytes

一个有趣的是 Math.abs(-2147483648) 结果还是 -2147483648. 在进行该运算前,要将其转化为long类型

Java

public int divide(int dividend, int divisor) {
        int sign = 1;
		if(dividend<0) sign = -sign;
		if(divisor<0) sign = -sign;
		long temp = Math.abs((long)dividend);
		long temp2 = Math.abs((long)divisor);
		long c = 1;
		while(temp>temp2){
			temp2 = temp2<<1;
			c = c<<1;
		}
		int res = 0;
		while(temp>=Math.abs((long)divisor)){
			while(temp>=temp2){
				temp-=temp2;
				res+=c;
			}
			temp2 = temp2>>1;
			c=c>>1;
		}
		if(sign>0) return res;
		else return -res;
    }
c++

int divide(int dividend, int divisor) {
        int sign = 1;
	    if(dividend<0) sign = -sign;
	    if(divisor<0) sign = -sign;
	    unsigned long c = 1;
	    unsigned long long tmp = abs((long long)dividend);
	    unsigned long long tmp2 = abs((long long)divisor);
	    while(tmp>tmp2){
	        tmp2 = tmp2<<1;
	        c=c<<1;
	    }
	    int result =0;
	    while(tmp>=abs((long long) divisor)){
	        while(tmp>=tmp2){
	            tmp = tmp - tmp2;
	            result += c;
	        }
	        tmp2 = tmp2>>1;
	        c=c>>1;
	    }
	    return sign*result;
    }



<think>嗯,用户让我介绍一下LeetCode的第29题,也就是“两数相除”。首先,我得先回忆一下这道题的具体内容。题目是要求不用乘法、除法和取模运算,实现两个整数的除法。对吧?那应该是在考察位运算或者加减法的巧妙应用。 接下来,用户可能想知道如何解决这个问题,以及需要注意的边界条件。比如,处理溢出情况,当被除数是最小负数,除数是-1的时候,结果会溢出,应该返回最大整数值。此外,所有数都要转成正数来处理,但原来的符号要记录下来,最后再调整结果的正负。 然后,我需要考虑如何用加减法或者位运算来模拟除法。通常,这可以通过不断减去除数的倍数来加速计算,比如每次将除数左移一位(相当于乘以2),直到不能再减为止。这样可以减少循环次数,提高效率。 还要注意,处理负数的时候,直接转成负数可能更好,因为负数的范围比正数大,比如-2^31转成正数会溢出。所以,可能应该将被除数和除数都转为负数来处理,这样避免溢出问题。 然后,具体的实现步骤可能包括:处理符号,转成负数,然后循环减去除数的倍数,同时记录累加的结果。比如,当被除数是-10,除数是-3的时候,初始余量是-10,除数是-3。第一次比较余量是否小于等于除数(这里都是负数,所以-10 <= -3),然后尝试减去除数的倍数,比如每次翻倍。 然后,用户可能需要具体的代码示例。这时候,我应该提供一个正确且高效的解决方案,用Java或者其他常用语言。比如,使用循环,每次将除数的值翻倍,直到超过被除数的当前余量,然后累加对应的商值。 最后,需要测试一些边界情况,比如被除数是-2147483648,除数是-1,这时候结果应该是2147483647,因为超出了整数最大值。另外,处理除数为1或-1的情况时,也需要快速返回结果,避免不必要的循环。 总结一下,解决这道题的关键在于处理符号转换,避免溢出,以及用位运算或倍增法来高效地计算结果。同时,需要注意各种边界条件,确保代码的鲁棒性。</think>LeetCode29题“两数相除”(Divide Two Integers)要求在不使用乘法、除法和取模运算的情况下,实现两个整数的除法运算。以下是逐步分析和解决方案: --- ### 问题描述 **目标**:计算整数除法 $dividend / divisor$,结果截断为整数(仅保留整数部分)。 **限制条件**: 1. 只能使用 **加减法** 和 **位运算**。 2. 假设运算结果在32位有符号整数范围内(即 $[-2^{31}, 2^{31}-1]$)。若结果溢出,返回 $2^{31}-1$。 --- ### 关键思路 #### 1. 处理符号 记录结果的符号(正或负),将被除数和除数统一转换为**负数**处理(避免正数溢出,如 $-2^{31}$ 转为正数会越界)。 #### 2. 倍增法加速 通过**指数级扩大除数倍数**(即每次翻倍),减少减法次数,优化时间复杂度至 $O(\log n)$。 #### 3. 边界条件 - 当 $dividend = -2^{31}$ 且 $divisor = -1$ 时,结果 $2^{31}$ 会溢出,需返回 $2^{31}-1$。 - 若除数为 $1$ 或 $-1$,可直接返回被除数或相反数。 --- ### 算法步骤 1. **符号处理**:根据 $dividend$ 和 $divisor$ 的符号确定最终结果的符号。 2. **转换负数**:将 $dividend$ 和 $divisor$ 转为负数。 3. **倍增法计算商**: - 每次尝试减去除数的最大倍数(即 $divisor \times 2^k$)。 - 通过左移运算(`<<`)快速计算倍数。 4. **处理溢出**:对结果进行越界检查。 --- ### 代码实现(Java) ```java class Solution { public int divide(int dividend, int divisor) { // 处理溢出情况 if (dividend == Integer.MIN_VALUE && divisor == -1) { return Integer.MAX_VALUE; } // 确定结果符号 int sign = (dividend > 0) ^ (divisor > 0) ? -1 : 1; // 转换为负数处理(避免溢出) dividend = dividend > 0 ? -dividend : dividend; divisor = divisor > 0 ? -divisor : divisor; int result = 0; while (dividend <= divisor) { int value = divisor; int quotient = 1; // 倍增法加速:每次尝试减去除数的最大倍数(value >= -2^30,避免越界) while (value >= (Integer.MIN_VALUE >> 1) && dividend <= (value << 1)) { value <<= 1; quotient <<= 1; } dividend -= value; result += quotient; } return sign == 1 ? result : -result; } } ``` --- ### 复杂度分析 - **时间复杂度**:$O(\log n)$,每次循环将问题规模减半。 - **空间复杂度**:$O(1)$,仅使用常数级额外空间。 --- ### 示例测试 1. **输入**:`dividend = 10`, `divisor = 3` **输出**:`3` **解释**:$10/3 = 3.333$,截断后为 $3$。 2. **输入**:`dividend = -2147483648`, `divisor = -1` **输出**:`2147483647` **解释**:结果溢出,返回最大值。 --- 通过符号处理、倍增法和边界条件控制,此方法能高效解决两数相除问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值