本题首先容易想到的就是不断的使除数自增,通过计数器判断增加了多少次, 那么增加的次数就是想要的答案。
// class Solution {
// public:
// int divide(int dividend, int divisor) {
// // 首先处理一些特殊情况
// // 如果被除数为1直接返回除数
// if(divisor == 1)
// return dividend;
// // 最终的结果的正负应该由flag决定
// bool flag = true;
// // 当两个数字有一个为负的时候结果为负
// if((dividend < 0 && divisor > 0) || (dividend > 0 && divisor < 0))
// flag = false;
// // 如果超出限制就要按照题目进行相应的处理
// if (dividend == INT_MIN && divisor == -1)
// return INT_MAX;
// // 因为负数的范围比正数范围大,因此将正数全部变为负数进行计算
// if(dividend > 0)
// dividend = -dividend;
// if(divisor > 0)
// divisor = -divisor;
// int ans = 0;
// while(1)
// {
// int a = dividend, b = divisor, cnt = 1;
// // 现在a,b都是负数
// if (a > b)
// break;
// // b < a && a < 2 * b的时候进行循环
// while(a - b <= b)
// {
// cnt += cnt;
// b += b;
// }
// ans += cnt;
// dividend -= b;
// }
// return flag ? ans : -ans;
// }
// };
class Solution {
public:
int divide(int dividend, int divisor) {
// 如果除数为1的话直接返回被除数即可
if(divisor == 1)
return dividend;
// 还需要一个最终用来决定正负的标记
bool flag = false;
// 只有两个数据同号的时候结果才为正
if((dividend > 0 && divisor > 0) || (divisor < 0 && dividend < 0))
flag = true;
// 还需要处理超出范围的问题,即被除数是最小的数,而除数是-1
// 因为负数的范围大,而正数的范围比负数的范围小1
if(dividend == INT_MIN && divisor == -1)
return INT_MAX;
// 我们将数据全部转为负数进行计算因为负数的范围更大
if(dividend > 0)
dividend = -dividend;
if(divisor > 0)
divisor = -divisor;
// 进行计算,我们可以通过不断的累加除数,
// 看除数经过多少次累加会超过被除数,这样就可以算出最终的结果
// int res = 0, cnt = 1;
int res = 0;
while(true)
{
// 为了方便标记,我们给除数被除数起别名
int a = dividend, b = divisor, cnt = 1;
// 因为这里是负数,因此我们考虑的时候需要在正数的基础上加上符号,也就是大小于号需要反向
if(a > b)
break;
// 当没有加到被除数那么大的时候就一直相加,计数器与最终的结果直接相关
while(a - b <= b)
{
cnt += cnt;
b += b;
}
// 当b大于a的时候就可以退出循环
res += cnt;
// 更新除数,这里注意都是负数,因此更新实际上使用的是减法
dividend -= b;
}
return flag ? res : -res;
}
};
本题主要影响速度的地方就是while循环,如果我们使用传统的方式一次增加一个的话,时间复杂度是O(n),那么在数字比较极端的时候会导致超时情况的出现,因此就有了下图的优化情况。每次尝试减去除数的倍数,在减到导致被除数为负数的时候退出,更新被除数,然后将减去了多少个除数的计数器结果加入到最终结果中。下一轮继续这种减法,然后循环,直到被除数小于除数。