Skip to main content

Recursion - Medium Level - Question 1

Recursion - Medium Level - Question 1


Leetcode 50 Pow(x, n)

Implement pow(x, n), which calculates x raised to the power n (i.e., x^n).

Constraints:

-100.0 < x < 100.0

-2^31 <= n <= 2^31-1

-10^4 <= x^n <= 10^4


Analysis:

If n == 0, then it always return 1;

If n == 1, it returns x.

For other n, consider the positive n first (since the negative value can be calculated with the positive ones).

If n is even, then pow(x, n) can be rewritten as pow(x, n/2) * pow(x, n/2); if odd, pow(x, n/2) * pow(x, n/2) * x. One of the key steps is that we just need to calculate pow(x, n/2) once, for the rest calls (or the second time to this question), just re-use the calculated results.

One corner case is pow(x, INT_MIN), which will cause overflow if simply timing with (-1). Some details need to take.


See the code below:

class Solution {
public:
    double myPow(double x, int n) {
        // the nagative case (handled the corner case)
        if(n<0) return 1.0/(x*myPow(x, -(n+1)));
        // base case
        if(n==0) return 1;
        // only calculate once
        double t = myPow(x, n/2);
        if(n&1) return t*t*x;
        return t*t;
    }
};


Question 2

Leetcode 1922 Count Good Numbers

A digit string is good if the digits (0-indexed) at even indices are even and the digits at odd indices are prime (2, 3, 5, or 7).


For example, "2582" is good because the digits (2 and 8) at even positions are even and the digits (5 and 2) at odd positions are prime. However, "3245" is not good because 3 is at an even index but is not even.

Given an integer n, return the total number of good digit strings of length n. Since the answer may be large, return it modulo 10^9 + 7.


A digit string is a string consisting of digits 0 through 9 that may contain leading zeros.


Constraints:

1 <= n <= 10^15


Analysis:

One of the keys is how to keep the question still the "same question".

It is clear that for this question, the total number is "5 * 4 * 5 * 4 * 5 * 4 ...", which are apparently repetitive operations. So we do not need to calculate it one by one, which is NOT the most efficient method.

We can divide it into two parts: depending on its length, 

 if the first part is even, then the second part can always start with 5, or the same as the original question;

if the first part is odd, then the second part will start with 4, which is NOT the same as the original question. But we make it to the same: since we know it will start with 4, we can re-write it as 4 * (the remaining part), where the remaining part starts with 5 again.

Another key is to just calculate one for each length.


See the code below:


class Solution {
public:
    int countGoodNumbers(long long n) {
        int mod = 1e9 + 7;
        if(n==0) return 1;
        if(n==1) return 5;
        if(n==2) return 20;
        long d = n/2, t = 1;
        if(n&1) {
            t = countGoodNumbers(d);
            // n = 3, 7, ...
            if(d&1) return t*4*t%mod;
            // n = 5, 9, ...
            return t*5*t%mod;
        }
        if(d&1) {
            // n = 6, 10, ...
            t = countGoodNumbers(d-1);
            return t*5%mod*4*t%mod;
        }
        // n = 4, 8, ...
        t = countGoodNumbers(d);
        return t*t%mod;
    }
};

A different way to divide the n:

We can always to take the power of 2 as the first part, then it will always to be even (even after division by half). 

See the code below:


class Solution {
public:
    int countGoodNumbers(long long n) {
        if(n==0) return 1;
        if(n==1) return 5;
        if(n==2) return 20;
        // this line (or base case) is needed
        if(n==3) return 100;
        long mod = 1e9 + 7, s = pow(2, floor(log2(n)));
        long t = countGoodNumbers(s/2)%mod;
        long r = countGoodNumbers(n - s)%mod;
        return (t*t%mod)*r%mod;
    }
};
Please be noted that the above code may re-calculate some intermediate states, but it is till fast enough to coverge.


Comments

Popular posts from this blog

Sweep Line

Sweep (or scanning) line algorithm is very efficient for some specific questions involving discrete intervals. The intervals could be the lasting time of events, or the width of a building or an abstract square, etc. In the scanning line algorithm, we usually need to distinguish the start and the end of an interval. After the labeling of the starts and ends, we can sort them together based on the values of the starts and ends. Thus, if there are N intervals in total, we will have 2*N data points (since each interval will contribute 2). The sorting becomes the most time-consuming step, which is O(2N*log(2N) ~ O(N*logN). After the sorting, we usually can run a linear sweep for all the data points. If the data point is labeled as a starting point, it means a new interval is in the processing; when an ending time is reached, it means one of the interval has ended. In such direct way, we can easily figure out how many intervals are in the processes. Other related information can also be obt...

Bit Manipulation - Example

  Leetcode 136 Single Number Given a non-empty array of integers nums, every element appears twice except for one. Find that single one. You must implement a solution with a linear runtime complexity and use only constant extra space. Constraints: 1 <= nums.length <= 3 * 10^4 -3 * 10^4 <= nums[i] <= 3 * 10^4 Each element in the array appears twice except for one element which appears only once. Analysis: If there is no space limitation, this question can be solved by counting easily. But counting requires additional space. Here we can use xor (^) operation based on some interesting observations:  A^A = 0, here A is any number A^0 = A, here A is any number Since all the number appears twice except one, then all the number appear even numbers will be cancelled out, and only the number appears one time is left, which is what we want. See the code below: class Solution { public: int singleNumber(vector<int>& nums) { int res = 0; for(auto ...

Algorithm Advance Outline

Who wants to read these notes? 1. the one who wants to learn algorithm; 2. the one who has a planned interview in a short amount of time, such as one month later; 3. purely out of curiosity; 4. all the rest. The primary purpose for these posts is to help anyone who wants to learn algorithm in a short amount of time and be ready for coding interviews with tech companies, such as, Amazon, Facebook, Microsoft, etc. Before you start, you are expected to already know:  1. the fundamentals of at least one programming language; 2. the fundamentals of data structures. If you do not have these basics, it is better to "google and read" some intro docs, which should NOT take large amount of time. Of course, you can always learn whenever see a "unknown" data structure or line in the codes. Remember, "google and read" is always one of keys to learning. Common algorithms: 1. Recursion 2. Binary search 3. Dynamic programming 4. Breadth-first search 5. Depth-first search...