反转正数和求指数幂的算法都挺简单的,写这两道题是为了记录一些在进行数值处理时要注意的边界条件和细节。
Reverse Integer
Reverse digits of an integer.
Example1: x = 123, return 321
Example2: x = -123, return -321
class Solution {
public:
int reverse(int x) {
int ans = 0;
while (x!=0) {
int temp = ans*10+x%10;
if (temp/10 != ans) return 0;
ans = temp;
x = x/10;
}
return ans;
}
};
Pow(x, n)
Implement pow(x, n).
基本思路:当n为偶数时,x^n = x^(n/2)*x^(n/2). 当n为奇数时,x^n = x^(n/2)*x(n/2)*x
在做题之前有几个问题是要考虑的:
1.0的0次方是什么……我百度了一下好像是不存在的……
2.n有可能是负数……(我一开始就忘了)
3.n是个int,如果它是负数的话,直接取反会溢出!(INTMAX:2147483647 INT_MIN:-2147483648)
class Solution {
public:
double myPow(double x, int n) {
if (n == 0) return 1.0;
if (n < 0) {
if (n == INT_MIN)
return 1.0/(helper(x,-(n+1))*x);
else
return 1.0/helper(x,-n);
} else {
return helper(x,n);
}
return 0;
}
double helper(double x, int n) {
if (n == 0) {
return 1.0;
}
else if (n % 2 == 0) {
double half = helper(x,n/2);
return half*half;
} else {
double half = helper(x,(n-1)/2);
return half*half*x;
}
}
};
String to Integer (atoi)
Implement atoi to convert a string to an integer.
基本思路:取出合法的数字串,从数字串最后一位向前遍历,然后根据它们所在的位数累加结果。
在做题之前有几个问题是要考虑的:
1.在字符串最开头的无效空格要去掉
2.字符串代表的数字的正负
3.由于返回的结果是整型,所以要考虑溢出
4.不能够被转换的类型,举几个代表性的例子:"-+2","-a234". 以下可能会有人以为不行但这道题是可以转换:"-2abc"->-2
以下是我AC的答案,但这个其实写得挺糟糕,因为很冗余并且效率不高,就一个个部分按部就班的完成。尤其是我在判断溢出的部分相当累赘,我利用的是字符串的字典序去判断的。并且其实这些步骤其实是可以在一趟内完成的……
***我在discuss板块里看见一个很精简的答案,主要是如果在转换数字时,如果从第一位开始遍历,那么每次只要把目前累加的结果乘以10再加上当前数字就可以了,那么就可以用到Reverse Integer里面提到的对溢出的判断。建议大家看一下https://leetcode.com/problems/string-to-integer-atoi/discuss/
int myAtoi(string str) {
if (str.size() == 0) {
return 0;
}
int i = 0;
bool neg = false;
int ans = 0;
// 去掉第一个非空格前的所有空格
bool allspace =false;
while (str[i] == ' ') {
if (i+1 < str.size()) {
i++;
} else {
allspace = true;
break;
}
}
if (allspace) return 0;
// 判断数字的正负
if (str[i] == '-') {
neg = true;
i++;
} else if(str[i] == '+') {
i++;
}
// 截出能够成功转换为数字的部分
string numpart = "";
while (i < str.size() && str[i] >= '0' && str[i] <= '9' ) {
numpart += str[i];
i++;
}
if (numpart == "") return 0;
// 去掉一串数字前无效的0
int j = 0;
while ( j< numpart.size() && numpart[j] == '0') {
j++;
}
if (j == numpart.size()) return 0;
// 处理溢出
if (numpart.size() <= 10) {
if (neg && numpart.size() == 10 &&numpart.substr(j) >= "2147483648") {
return INT_MIN;
}
if (!neg && numpart.size() == 10 &&numpart.substr(j) >= "2147483647") {
return INT_MAX;
}
} else {
if (neg) return INT_MIN;
else return INT_MAX;
}
// 将数字根据它所在的位数累加起来
int pos = 1;
for (int k = numpart.size()-1; k >= j; k--) {
ans += (numpart[k]-'0')*pos;
pos *= 10;
}
if (neg) {
ans *= -1;
}
return ans;
}
Divide Two Integers
Divide two integers without using multiplication, division and mod operator.
If it is overflow, return MAX_INT.
基本思路:由于不给用乘、除、取模运算符,所以只能不断通过从被除数中减去除数直到被除数小于除数,并且记录减去了多少个除数来获得结果。比较简单的方法是每次都减去一个除数,而加快这个过程的方法是每次减去多个除数,怎么减呢?利用位移运算符将除数尽可能多地左移k次(左移后的结果不能超过被除数),相当于是divisor*pow(2,k), 可以看成被除数中包括了pow(2,k)个divisor,那么在这次中我们将可以减去pow(2,k)个除数。再利用同样的方法,在剩余的被除数中不断减去2的某个次幂的除数直到被除数无法被除数整除。int divide(int dividend, int divisor) {
// overflow?
if (dividend == INT_MIN && divisor == -1) return INT_MAX;
if (divisor == 0) return INT_MAX;
if (divisor == INT_MIN) {
return dividend == INT_MIN ? 1 : 0;
}
// positive?
bool Negative = (dividend ^ divisor) >> 31;
long divident = labs(dividend);
divisor = abs(divisor);
int times = 0;
int t = 0;
while (divident >= divisor) {
while (divident >= (divisor << times)) {
int d = (divisor << (times+1));
if (d/2 == (divisor << times) && divident >= d) times++;
else break;
}
t += 1<<times;
divident -= (divisor<<times);
times=0;
}
return Negative?-t:t;
}
1.除数和被除数的最高位是否相同,异或结果为1表示不同,即结果为负
参考资料:http://www.cnblogs.com/grandyang/p/4125588.html
https://leetcode.com/problems/string-to-integer-atoi/discuss/
https://discuss.leetcode.com/topic/15568/detailed-explained-8ms-c-solution