Leetcode 50. Pow(x, n)碰到的一些问题

首先这是题目

Implement pow(x, n), which calculates x raised to the power n (xn).

Example 1:

Input: 2.00000, 10
Output: 1024.00000
Example 2:

Input: 2.10000, 3
Output: 9.26100
Example 3:

Input: 2.00000, -2
Output: 0.25000
Explanation: 2-2 = 1/22 = 1/4 = 0.25
Note:

-100.0 < x < 100.0
n is a 32-bit signed integer, within the range [−231, 231 − 1]

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/powx-n
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

这个问题其实就是自己写一个Pow函数,来计算x的n次幂

第一时间我想到的是二分法

假设要求 2 48 = 2 24 ∗ 2 24 = 2 12 ∗ 2 12 ∗ 2 12 ∗ 2 12 = 2 6 ∗ 2 6 ∗ 2 6 ∗ 2 6 ∗ 2 6 ∗ 2 6 ∗ 2 6 ∗ 2 6 = 2 3 ∗ 2 3 ∗ 2 3 ∗ 2 3 ∗ 2 3 ∗ 2 3 ∗ 2 3 ∗ 2 3 ∗ 2 3 ∗ 2 3 ∗ 2 3 ∗ 2 3 ∗ 2 3 ∗ 2 3 ∗ 2 3 ∗ 2 3 2^{48}=2^{24}*2^{24}=2^{12}*2^{12}*2^{12}*2^{12}=2^{6}*2^{6}*2^{6}*2^{6}*2^{6}*2^{6}*2^{6}*2^{6}=2^{3}*2^{3}*2^{3}*2^{3}*2^{3}*2^{3}*2^{3}*2^{3}*2^{3}*2^{3}*2^{3}*2^{3}*2^{3}*2^{3}*2^{3}*2^{3} 248=224224=212212212212=2626262626262626=23232323232323232323232323232323
因为我还是更加熟悉c#/Java所以先选择了Java

import java.util.Scanner;

class Main{
	public static void main(String[] args) {
		double x;
		int n;
		Scanner sc = new Scanner(System.in);
		System.out.println("Pls input x");
		x = sc.nextDouble();
		System.out.println("Pls input n");
		n = sc.nextInt();
		System.out.println(myPow(x, n));
	}
	
	static double myPow(double x, int n) {
		int N = n;
		if (n == 0)
			return 1;
			
		return N > 0 ? CalPow(x, N) : 1 / CalPow(x, -N);
	}
	
	static double CalPow(double x, int N)
	{
		if (N == 1)
			return x;
		int n = N / 2;
		if (N % 2 != 0)
		{
			return x * CalPow(x, n) * CalPow(x, n);
		}
		return CalPow(x, n) * CalPow(x, n);
	}
}

一跑发现有溢出了,大晚上脑子有点懵,还以为是double溢出,但是浮点数是以 符号 指数 小数 来储存的,不太可能溢出啊。后来看了看大佬们的题解,才发现是在N取-128的时候变成正数造成的溢出
在这里插入图片描述
所以还是得谨慎一点才行
修改之后

import java.util.Scanner;

class Main{
	public static void main(String[] args) {
		double x;
		int n;
		Scanner sc = new Scanner(System.in);
		System.out.println("Pls input x");
		x = sc.nextDouble();
		System.out.println("Pls input n");
		n = sc.nextInt();
		System.out.println(myPow(x, n));
	}
	
	static double myPow(double x, int n) {
		long N = n;
		if (n == 0)
			return 1;
		return N > 0 ? CalPow(x, N) : 1 / CalPow(x, -N);
	}
	
	static double CalPow(double x, long N)
	{
		if (N == 1)
			return x;
		int n = (int)N / 2;
		if (N % 2 != 0)
		{
			return x * CalPow(x, n) * CalPow(x, n);
		}
		return CalPow(x, n) * CalPow(x, n);
	}
}

舒服多了,可是新的问题又产生了。对,就是该死的超时,递归的时候我每次都要再重新算一遍结果,然后它就超时了

import java.util.Scanner;

class Main{
	public static void main(String[] args) {
		double x;
		int n;
		Scanner sc = new Scanner(System.in);
		System.out.println("Pls input x");
		x = sc.nextDouble();
		System.out.println("Pls input n");
		n = sc.nextInt();
		System.out.println(myPow(x, n));
	}
	
	static double myPow(double x, int n) {
		long N = n;
		if (n == 0)
			return 1;
		return N > 0 ? CalPow(x, N) : 1 / CalPow(x, -N);
	}
	
	static double CalPow(double x, long N)
	{
		if (N == 1)
			return x;
        double num = CalPow(x, N / 2);
		if (N % 2 != 0)
		{
			return x * num * num;
		}
		return num * num;
	}
}

OK,问题解决!

然后是官方给出的二进制解法

class Solution {
public:
    double quickMul(double x, long long N) {
        double ans = 1.0;
        // 贡献的初始值为 x
        double x_contribute = x;
        // 在对 N 进行二进制拆分的同时计算答案
        while (N > 0) {
            if (N % 2 == 1) {
                // 如果 N 二进制表示的最低位为 1,那么需要计入贡献
                ans *= x_contribute;
            }
            // 将贡献不断地平方
            x_contribute *= x_contribute;
            // 舍弃 N 二进制表示的最低位,这样我们每次只要判断最低位即可
            N /= 2;
        }
        return ans;
    }

    double myPow(double x, int n) {
        long long N = n;
        return N >= 0 ? quickMul(x, N) : 1.0 / quickMul(x, -N);
    }
};

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/powx-n/solution/powx-n-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

嚯,真是妙啊。

因为每个 x n x^n xn都会被拆成 x n / 2 ∗ x n / 2 x^{n/2}*x^{n/2} xn/2xn/2或者是 x n / 2 ∗ x n / 2 ∗ x x^{n/2}*x^{n/2}*x xn/2xn/2x
假设我们要求 x 77 x^{77} x77
那么 x → x 2 → x 4 → x 9 → x 19 → x 38 → x 77 x \rightarrow x^{2} \rightarrow x^{4} \rightarrow x^{9} \rightarrow x^{19} \rightarrow x^{38} \rightarrow x^{77} xx2x4x9x19x38x77
其中在 x 77 x^{77} x77 x 19 x^{19} x19 x 9 x^{9} x9在拆分的时候要多拆一个x
x 77 x^{77} x77被拆开时,需要多乘一个 x x x
x 19 x^{19} x19被拆开时,需要多乘四个 x x x,就有 2 2 = 4 2^{2}=4 22=4
x 9 x^{9} x9被拆开时,需要多乘八个 x x x,就有 2 2 2 = 8 2^{2^2}=8 222=8
然后最初的 x x x被拆了6次,那么就有 2 6 = 64 2^6=64 26=64
将它们全部相乘 x ∗ x 4 ∗ x 8 ∗ x 64 x*x^4*x^8*x^{64} xx4x8x64结果正好为 x 77 x^{77} x77
而其中的1,4,8,64 恰好又是77的二进制数 ( 1001101 ) 2 (1001101)_2 (1001101)2中的每个1

总结

这个题自己犯错的主要问题就是没有考虑全面,多注意一些小细节,以及多思考怎样才能计算次数更少才行,一开始return 函数*函数那就要多算很多遍。
一些问题可以尝试从二进制下手,只要找出其中的规律,解决问题所需的时间和空间可能会大大减少。

你可能感兴趣的:(Leetcode,算法)