剑指Offer 16-17.数值的整数次方

156 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第12天,点击查看活动详情

题目:实现pow(x,n)pow(x, n),即不使用库函数实现数的幂运算。

解题思路

不考虑那么多,计算一个数的n次方,直接将这个数相乘n此即可得到答案,代码如下:

public double myPow(double x, int n) {
    double res = 1.0;
    boolean flag = n > 0;
    n = n > 0 ? n : -n;
    for (int i = 0; i < n; i++) {
        if (flag) {
            res *= x;
        } else {
            res /= x;
        }
    }
    return res;
}

最终超时,其实就算不超时也应该通过不了,因为 -2147483648 这个用例。

我们前面剪绳子的时候对一个数取余使用了循环取余法和快速幂取余,其中循环取余就是上面的方法,而快速幂显然计算时间复杂度更低,使用快速幂方法来计算代码如下:

public double myPow2(double x, int n) {
    double res = 1.0;
    boolean flag = n > 0;
    n = n > 0 ? n : -n;
    while(n!=0){
        if(n % 2 == 1){
            res *= x;
        }
        x *= x;
        n /= 2;
    }
    if(flag) return res;
    return 1/res;
}

最终最后一个用例没有通过,也就是-2147483648 , 因为Java中int的取值范围是-2147483648到2147483647 ,因此如果直接取反返回的还是原数(越界了用补码表示),因此需要将数先转long,代码如下:

public double myPow3(double x, int n) {
    double res = 1.0;
    boolean flag = n > 0;
    long b = n;
    b = b > 0 ? b : -b;
    while(b!=0){
        if(b % 2 == 1){
            res *= x;
        }
        x *= x;
        b /= 2;
    }
    if(flag) return res;
    return 1/res;
}

另一种思路我们可以用递归来计算,递归的思路其实和上面是一样的,代码如下:

public double myPow4(double x, int n) {
    long b = n;
    return b>=0?dfs(x, n):1.0/dfs(x, -n);
}

public double dfs(double x, int n){
    if(n == 0) return 1.0;
    double res = dfs(x, n>>1);
    return n%2==0?res*res:res*res*x;
}

剑指Offer 17、打印从1到最大的n位数

题目: 输入数字 n,按顺序打印出从 1 到最大的 n 位十进制数。比如输入 3,则打印出 1、2、3 一直到最大的 3 位数 999。

解题思路

如果不考虑大数问题,则此题变得没有意义,代码如下:

public int[] printNumbers(int n) {
    int pow = (int) Math.pow(10, n)-1;
    int[] res = new int[pow];
    for(int i=0;i<pow;i++){
        res[i] = i + 1;
    }
    return res;
}

考虑大数问题的在下一篇补上。