The integer power of the offer 16 value of the sword finger

Posted by Aethaellyn on Tue, 08 Feb 2022 23:06:07 +0100

Realize pow(x, n), that is, calculate the N-power function of X (i.e., xn). Library functions should not be used and large numbers should not be considered.

Example 1:

Input: x = 2.00000, n = 10
Output: 1024.00000

Example 2:

Input: x = 2.10000, n = 3
Output: 9.26100

Example 3:

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

Tips:

-100.0 < x < 100.0
-231 <= n <= 231-1
-104 <= xn <= 104

Source: LeetCode
Link: https://leetcode-cn.com/problems/shu-zhi-de-zheng-shu-ci-fang-lcof
The copyright belongs to Lingkou network. For commercial reprint, please contact the official authorization, and for non-commercial reprint, please indicate the source.

The topic is very simple, but this topic needs to fully consider the boundary and special situations, such as the case where x is negative and n is negative. These situations need to be taken into account.

If these situations are taken into account, it is easy to write down the following solutions:

class Solution {
public:
    double myPow(double x, int n) {
         bool flage = (n >= 0) ? true : false;
         double res = 1;
         if(x == 0) return 0;
         if(x == 1) return 1;
         int abs_n = flage ? n : -n;
         //int falge_res = ( abs_n%2 == 0) ? 1 :( x >= 0) ? 1 : -1;
         if(flage){
             while(abs_n--){
                 res  = res*x;
             }
         }
         else{
             while(abs_n--)
             res = res*(1/x);
         }
         
         return res;//*falge_res ; 
    }
};

But there is a special test case that can't pass:

2.00000
-2147483648

Why can't this test case pass?
Because the value is stored in the computer with complement, people with a little computer foundation will know, int32_ The range of positive and negative numbers of T is inconsistent. Therefore, you can use long variables to get n first, and then reverse long numbers to avoid overflow.

long b = n;
.....
int abs_n = flage ? b: -b;

At this time, the submission is found to have timed out, because the complexity at this time is O(n). The larger the index, the longer the time-consuming. It seems that the problem requires us to reduce the complexity.

Then we remember the dichotomy,

a^n = a^(n/2)*a^(n/2) n Even number
a^n = a^((n-1)/2)*a^((n-1)/2)*a n Odd number

In this way, the complexity is reduced to O(log n).

It should be noted that if n is an even number, the division can be operated with displacement. Similarly, if n is an odd number, (n-1) > > 1 = = n > > 1, so the operation with displacement can not be reduced by one

The idea of recursion is relatively simple,

Explain two points,
1: In order to simplify the judgment, simply make a judgment at the function entry and uniformly process the data into positive numbers
2: Here, recursive functions are proposed separately for easy understanding

As follows:

class Solution {
public:
    double kernel(double x, long n){
        if( n == 0) return 1;
        if( n == 1) return x;
        double res = kernel(x,n>>1);
        res = res*res;
        if((n & 0x1) == 1)
           res = res*x;
        return res;   
    }
    double myPow(double x, int n) {
         long b = n;
         bool flage = (b >= 0) ? true : false;
         double res = 1.0;
         if(x == 0) return 0;
         if(x == 1) return 1;
         long abs_n = flage ? b : -b;
         if(!flage){
             x = 1/x;
             abs_n = -b;
         }
         res = kernel(x,abs_n);
         return res;
    }
};

Recursion is easy to understand, but each recursive call of the program will incur some overhead. Therefore, iterative methods are also provided here for reference.

class Solution {
public:
    double myPow(double x, int n) {
         long b = n;
         bool flage = (b >= 0) ? true : false;
         double res = 1.0;
         if(x == 0) return 0;
         if(x == 1) return 1;
         
         long abs_n = flage ? b : -b;
         
         if(!flage){
             x = 1/x;
             abs_n = -b;
         }
        while(abs_n > 0){
            if( (abs_n&1) == 1) res*=x;
            x = x*x;
            abs_n = abs_n >> 1;
        }
         return res;
    }
};

Like the previous steps, two points need to be explained,
1: N > > 1 must be assigned to N. direct n > > 1 has no side effects, and the value of n will not change
2: Here, when n is an even number, x=x*x, which is not assigned to res, will it not lead to omission? The answer is no, because even number divided by 2 must be odd, so the value of res is in ABS_ Update to when n = 1.

We can write recursive code first, and then change it to iterative form.

Topics: Algorithm leetcode