LeetCode 两数相除

给定两个整数,被除数 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。
方法一:最直接的算法当然是直接相减,模拟运算除法,然而当数据量大的时候,时间复杂度相当的大。。。

class Solution {
public:
    int divide(long long dividend, long long divisor) {
		if (dividend == INT_MIN && divisor == -1){
			return INT_MAX;
		}
		if (divisor == 1){//如果除数是1,则无需相减,直接返回
			return dividend;
		}
		if (divisor == -1){
			return -dividend;
		}
		bool resultFlag = false;//结果是否为负数的flag
		if (!((dividend >= 0 && divisor >= 0) || (dividend < 0 && divisor < 0))){
			//如果非同号
			resultFlag = true;
		}
		if (dividend < 0){
			dividend = -dividend;
		}
		if (divisor < 0){
			divisor = -divisor;
		}
		long long result = 0;//结果
		while (dividend >= divisor){//一直相减
			dividend -= divisor;
			++result;
		}
		if (resultFlag){//如果标识结果为负数
			result = -result;
		}
		return result;
	}
};

在这里插入图片描述
上述方法感觉就是变相的暴搜。。。
方法二:下面将采用“以空间换时间”的策略,对上述算法进行优化。即使用一个数组,计算好一定数量的除数的n倍,这样可以减少相减的次数。

int divide(long long dividend, long long divisor) {
	if (dividend == INT_MIN && divisor == -1){
		return INT_MAX;
	}
	if (divisor == 1){//如果除数是1,则无需相减,直接返回
		return dividend;
	}
	if (divisor == -1){
		return -dividend;
	}
	bool resultFlag = false;//结果是否为负数的flag
	if (!((dividend >= 0 && divisor >= 0) || (dividend < 0 && divisor < 0))){
		//如果非同号
		resultFlag = true;
	}
	if (dividend < 0){
		dividend = -dividend;
	}
	if (divisor < 0){
		divisor = -divisor;
	}
	//tempNValue[i]代表i倍的divisor(零除外)
	long long tempNValue[100] = { INT_MAX, divisor};
	int maxIndex = 1;//可以计算的最大的n倍divisor的值
	while (maxIndex < 99){
		tempNValue[++maxIndex] = tempNValue[maxIndex] + divisor;
	}
	long long result = 0;//结果
	int beginIndex = maxIndex;
	while (beginIndex >= 1){//一直相减
		while (dividend >= tempNValue[beginIndex]){
			dividend -= tempNValue[beginIndex];
			result += beginIndex;
		}
		--beginIndex;
	}
	if (resultFlag){//如果标识结果为负数
		result = -result;
	}
	return result;
}

在这里插入图片描述
虽然时间复杂度减少了很多,但是击败的用户很少,肯定与主流做法有很大的差距。。。
经翻阅前辈的算法,发现一种移位色解法。

这道题的基本思路使用移位和加减法替代乘除,因为任何INT除法运算可以表示为 X = y * N, N = 2^0 + 2^1 + 2^2 + 2^3 + ......。 这道题的难点在于 假设我们的环境只能存储 32 位有符号整数,其数值范围是 [−2^31, 2^31 − 1]。本题中,如果除法结果溢出,则返回 2^31 − 1。 这会造成两个麻烦:

移位有限制,无法使用long等类型
针对INT_MIN,无法直接转换为正数 对策:
提前判断是否移位越界
先提前dividend += abs(divisor),然后结果加1,然后在转为正数计算即可 附代码
class Solution {
public:
    int divide(int dividend, int divisor) {
        if(divisor == -1 && dividend == INT_MIN) return INT_MAX;
        if(divisor == 1 && dividend == INT_MIN) return INT_MIN;
        int sign = (dividend > 0 && divisor < 0) || (dividend < 0 && divisor > 0) ? -1 : 1;
        if(divisor == INT_MIN) return dividend == INT_MIN ? 1 : 0;
        divisor = abs(divisor);
        
        int res = 0;        
        if(dividend == INT_MIN){
            res += 1;
            dividend += divisor;
        }
        
        dividend = abs(dividend);
        if(divisor  > dividend) return res*sign;
        while(dividend != 1 && dividend != 0 && dividend > divisor){
            int tmp = divisor; int cnt = 1;
            while(dividend > (tmp << 1)){
                if((tmp << 1)  < tmp) break;
                tmp = tmp << 1;
                cnt = cnt << 1;
            }
            dividend -= tmp;
            res += cnt;
        }
        res = (res + (dividend < divisor ? 0 : 1)) * sign;
        return res;
    }
};

猜你喜欢

转载自blog.csdn.net/qq_41855420/article/details/86665152
今日推荐