leetcode 29. 两数相除 中等 未完全解决
首先是我自己写出来的方法,复杂度为O(n)
一、使用long类型
class Solution {
public:
long divide2(long dividend,long divisor){
if(dividend < 0 && divisor < 0) return divide2(-dividend,-divisor);
else if(dividend < 0 && divisor > 0) return -divide2(-dividend,divisor);
else if(dividend > 0 && divisor < 0) return -divide2(dividend,-divisor);
if(divisor == 1) return dividend;
if(dividend < divisor) return 0;
long num = 0;
while(dividend > 0){
dividend -= divisor;
num++;
}
if(dividend < 0) return num-1;
return num;
}
int divide(int dividend, int divisor) {
long MAX = pow(2,31);
long num = divide2(dividend,divisor);
if(num > MAX-1) return MAX-1;
else if(num < -MAX) return -MAX;
return num;
}
};
用时和消耗内存表现特别差
二、不使用long类型
测试点会有很多 -2^31 2^31-1 1 -1 这些地方选。
特别是 -2^31 ,不能将它转换为正数,只能单防,剪枝
class Solution {
public:
int divide2(int dividend,int divisor){
if(dividend < 0 && divisor < 0) return divide2(-dividend,-divisor);
else if(dividend < 0 && divisor > 0) return -divide2(-dividend,divisor);
else if(dividend > 0 && divisor < 0) return -divide2(dividend,-divisor);
if(dividend < divisor) return 0;
int num = 0;
while(dividend > 0){
dividend -= divisor;
num++;
}
if(dividend < 0) return num-1;
return num;
}
int divide(int dividend, int divisor){
if(dividend == divisor) return 1;
if(divisor == INT_MIN) return 0;
if(dividend == INT_MIN && divisor == -1) return INT_MAX;
if(divisor == 1) return dividend;
if(divisor == -1) return -dividend;
if(dividend == INT_MIN){
int num = 0;int flag;
if(divisor > 0) flag = 1;
else flag = -1;
while(dividend < 0){
dividend = dividend + divisor*flag;
num++;
}
if(dividend != 0) return (num-1)*-1*flag;
return num*-1*flag;
}
return divide2(dividend,divisor);
}
};
内存表现好了一点,耗时还是很大
最优的方法应该是使用快速乘
因为有数据范围限制,负数的范围比正数更大。所以题解基本上都是将两个数都转为负数进行计算
为了更好理解算法思想,我先使用long类型,两个数都转为正数
class Solution {
public:
long divide2(long dividend,long divisor){
bool flag = true;
if(dividend > 0 && divisor < 0 || dividend < 0 && divisor > 0) flag = false;
if(dividend < 0) dividend = -dividend;
if(divisor < 0) divisor = -divisor;
vector<pair<long,long>> exp;
for(long i = divisor,j = 1; i <= dividend; i += i, j += j){
exp.push_back({i,j}); //将被除数的2^k倍数和2^k对应关系保存起来
}
int res = 0;
for(int i = exp.size()-1; i >= 0; i--){
if(exp[i].first <= dividend){
res += exp[i].second;
dividend -= exp[i].first;
}
}
if(flag == false) return -res;
if(res == INT_MIN) return INT_MAX;
return res;
}
int divide(int dividend, int divisor){
if(dividend == divisor) return 1;
if(divisor == INT_MIN) return 0;
if(dividend == INT_MIN && divisor == -1) return INT_MAX;
if(divisor == 1) return dividend;
if(divisor == -1) return -dividend;
if(dividend == 0) return 0;
return divide2(dividend,divisor);
}
};
不使用long ,两个数都转换为负数
class Solution {
public:
int divide(int dividend, int divisor){
if(dividend == divisor) return 1;
if(divisor == INT_MIN) return 0;
if(dividend == INT_MIN && divisor == -1) return INT_MAX;
if(divisor == 1) return dividend;
if(divisor == -1) return -dividend;
if(dividend == 0) return 0;
bool flag = true;
if(dividend > 0 && divisor > 0 || dividend < 0 && divisor < 0) flag = false;
if(dividend > 0) dividend = -dividend;
if(divisor > 0) divisor = -divisor;
if(dividend > divisor) return 0;//被除数的绝对值比除数小
vector<pair<int,int>> exp;
for(int i = divisor,j = -1; i >= dividend; i += i, j += j){
//一开始除数是大于被除数的
exp.push_back({i,j}); ////将被除数的2^k倍数和2^k对应关系保存起来
if(i < INT_MIN>>1) break; //说明下一次i*2就会超过int的左范围了
//if(i < INT_MIN/2) break;
}
int res = 0;
for(int i = exp.size()-1; i >= 0; i--){
if(exp[i].first >= dividend){
res += exp[i].second;
dividend -= exp[i].first; //exp[i].first本身就是负的,越减只会让dividend越靠近0
}
}
if(flag == false) return -res;
//if(res == INT_MIN) return INT_MAX; //只有INT_MIN/1结果才是INT_MIN,但前面已经剪枝了
return res;
}
};