Skip to content
本页目录

OF16-数值的整数次方

题目描述

https://leetcode.cn/problems/shu-zhi-de-zheng-shu-ci-fang-lcof

实现 pow(x, n) ,即计算 x 的 n 次幂函数(即,$$x^n$$)。不得使用库函数,同时不需要考虑大数问题。

示例 1:

输入:x = 2.00000, n = 10
输出:1024.00000

示例 2:

输入:x = 2.10000, n = 3
输出:9.26100

示例 3:

输入:x = 2.00000, n = -2
输出:0.25000
解释:2^-2 = 1/22 = 1/4 = 0.25

提示:

$$ -100 < x < 100 \ -2^{31} <= n <= 2^{31-1} \ -10^4 <= x^n <= 10^4 $$

思路分析

题目不得使用库函数,不需要考虑大数问题,所以我们可以用常规的解法。

需要注意的点

  1. n 是 “负号” 的处理, 需要将结果用去除1

  2. x是负数处理,根据n是否是单数,是单数则最后带符号,否则是正数

  3. 以上两个处理完,就可以按照正常的规则处理,注意递归可能超时,需要使用循环的方式 折半乘方 来计算,注意是否单数

  4. 注意 负数的溢出,当 n 是 -2147483648 时, -n 同样还是这个数,会产生死循环

    https://www.cnblogs.com/gexin/p/7485231.html

    对int类型最小值INT_MIN取负值结果不变

    在32位系统中,int类型的最大值是0x7fffffff(即除了最高的1Bit其他31位都为1),而最小值是0x80000000(除了最高1bit,其他31位都为0)。

    显然,对于最小值求负数是不存在的,为什么会使最小值本身呢?

    这是由于在计算负运算时,是针对int类型数据进行“取反加一”操作。这样对于最小值而言,“取反加一”还是本身保持不变。

    另外,针对整数的计算,都是从位的角度的进行的。比如,int类型数据的最大值(0x7fffffff )加1,会得到int类型的最小值(0x80000000);而对于unsigned int类型的0x7fffffff 加1 ,也会得到0x80000000,这在位的角度来看都是一致的。

    c
    #include <stdio.h>
    int main()
    {
    	int a = 0x80000000;	
    	int b = 0x7fffffff;
    	printf("INT_MIN and its' negative is :\n %d, %d\n\n", a, -a);
    	printf("INT_MAX and INT_MAX+1 is :\n %d, %d\n\n", b, b+1);
    	printf("unsigned(INT_MAX)  and unsigned(INT_MAX+1) is :\n %u, %u\n\n", b, b+1);   	
    	return 0;
    }
    
    /*******输出如下****************/
    Process started >>>
    INT_MIN and its' negative is :
     -2147483648, -2147483648
    INT_MAX and INT_MAX+1 is :
     2147483647, -2147483648
    unsigned(INT_MAX)  and unsigned(INT_MAX+1) is :
     2147483647, 2147483648
    <<< Process finished. (Exit code 0)
    

实现代码

第一次实现,超出时间限制

csharp
public class Solution {
    public double MyPow(double x, int n) {
        if(n == 0){
            return 1;
        }
        if(n == 1){
            return x;
        }
        //指数负数处理
        if(n < 0){
            return 1.0 / MyPow(x, -n);
        }
        //x负数处理
        if(x < 0){
            if(n % 2 == 1){
                return -MyPow(-x, n);
            }
            else{
                return MyPow(-x,n);
            }
        }
        //折半计算
        double result = MyPow(x, n/2) * MyPow(x, n/2);
        if(n % 2 == 1){
            result *= x;
        }
        return result;
    }
}

第二次实现

csharp
public class Solution {
    public double MyPow(double x, int n) {
        if(n == 0){
            return 1;
        }
        if(n == 1){
            return x;
        }
        //指数负数处理
        if(n < 0){
            return 1.0 / MyPow(x, -n);
        }
        //x负数处理
        if(x < 0){
            if(n % 2 == 1){
                return -MyPow(-x, n);
            }
            else{
                return MyPow(-x,n);
            }
        }
        //折半计算
		double result = 1.0;
        while(n > 0){
            //如果是2的倍数+1,那么就乘以这个数,在计算倍数
            if(n & 1 == 1){
                result *= x;
            }
            //折半n,并且将x翻倍,最终的时候 n == 1 会乘以到 result 里面
            x = x * x;
            n>>=1;
        }        
        return result;
    }
}

改代码执行的时候,会溢出

1.00000
-2147483648
Stack overflow : repat 6249651 times
检查这种情况应该是 n 负数处理的时候出错了
-(-2147483648) == ?
//执行下面代码可以知道 -m = m, 都会输出 -2147483648,所以会重复不停计算
int m = -2147483648;
Console.WriteLine(m);
Console.WriteLine(-m);

需要将代码

csharp
if(n < 0){
	return 1.0 / MyPow(x, -n);
}

改成

csharp
if(n < 0){
    return 1.0/(x * MyPow(x, -(n+1)));
}

参考线上代码 : 十分精炼

csharp
public class Solution {
    public double MyPow(double x, int n) {
        double ans = 1.0;
        if(n==0) return ans;
        if(n<0)
        {
            ans = MyPow(1/x,-(n+1));//防溢出
            ans*=1/x;
        }
        while(n>0)
        {
            if((n&1)==1) ans*=x;
            x*=x;
            n>>=1;
        }
        return ans;
    }
}

第二遍做:注意折半的时候,放大 x *= x;

csharp
public class Solution {
    public double MyPow(double x, int n) {
        if(x == 0){
            return 0;
        }
        if(n == 0){
            return 1;
        }
        //判断n负数
        double result = 1.0;
        if(n < 0){
            //考虑到 n = int.MinValue 时, -n 还是这个值,所以不能直接用 MyPower(1/x,-n)
            result = MyPow(1 / x, -(n+1));
            result *= 1/x;
        }
        while(n > 0){
            //将 n 除以 2, 那么原来的值就 平方,如果有单数,则 额外乘以 x
            if( n % 2 == 1){
                result *= x;
            }
            x*=x;
            n = n / 2;
        }
        return result;
    }
}

参考代码:复习20220503

csharp
public class Solution {
    public double MyPow(double x, int n) {
        //直接循环计算会超时
        double result = 1.0;
        if(n == 0){
            return result;
        }
        if(n < 0){
            // -(n+1) 放置溢出 int.MinValue 溢出
            result = MyPow(1/x, -(n+1));
            result *= 1/x;
            return result;
        }
        while(n > 0){
            //指数逐渐缩小
            if(n % 2 == 1){
                result *= x;
            }

            n = n/2;
            //根数逐渐放大
            x *= x;
        }
        return result;

    }
}

Released under the MIT License.