[sword finger offer] 10- I. Fibonacci sequence (it takes three hours to study something more essential)

Posted by The_Stranger on Sat, 12 Feb 2022 06:00:21 +0100

Say something before brushing

If you want to cut the length of the article, you will say it in addition to the length of the code,

Because too much time is wasted in writing articles!

In fact, it's not difficult to brush the questions. What's difficult is to insist!

This column is the classic title of sword finger offer,

And record your understanding and learning process in this blog!

Topic Introduction (LINK)

I won't introduce too much about the topic. Copying is of little significance. I'll post a link directly here!

LeetCode link: Click here!

NowCoder link: Click here!

Thoughts / ideas

1. Initial idea / final idea

Today's topic is relatively simple. Everyone must have seen it!

But I want to pass on a concept: pruning and double counting!

In the past, the efficiency of directly writing recursive schemes was very low. How to solve it?

There is a pruning strategy!

Here I will let you know some details of actual recursion and the cost of time, and solve the cost of time!

iteration

Pay attention to the critical problem. When n == 1, return 1 directly;, Can!

Don't write the rest. Everyone will. Just look at the code below and don't comment on private letters!

In fact, the iterative code is a dynamic programming code,

It's just that the topic is too simple for everyone to understand!

However, this is not the point, the point is the following recursion!

recursion

When I was studying C language, I wrote a function article, which mentioned the problem of Fibonacci sequence recursion, You can have a look first!

Please be sure to look at the recursion and iteration part at the back of the above article. If it's a big man, when I didn't say it, I still suggest taking a look. Don't forget to praise it by the way!

Now I know that Fibonacci recursion is very time-consuming. If you write such code when OJ (now coder or LeetCode), it will "explode"!

I tested it. It passed when NowCode was written as recursion. I can only say that the test cases of NowCoder are not written well!

In contrast, LeetCode is still a cow!

Now, what we need to do is how to reduce consumption and solve a large number of repeated calculations!

Here you can use Map to perform relevant pruning actions!

2. Precautions

Attention: there is a small change in the title of LeetCode and NowCoder:

The following description of LeetCode is as follows: the answer needs to take the module 1e9+7 (1000000007). If the initial calculation result is 1000000008, please return 1.

There is a good way: the efficiency of taking mold is relatively low, so subtraction is simpler!

Don't understand. Look down:

It is time-consuming to calculate the remainder. You can subtract 100000007. Because the first result greater than 100000007 will subtract 100000007, there will never be 100000007 greater than or equal to twice. In this way, the remainder of 100000007 will be reduced to subtracting 100000007.

Iterative implementation

//NowCoder version
public class Solution {
    public int Fibonacci(int n) {
        if (0 == n) {
            return 0;
        }
        //The following if statement can be omitted on the premise that the value of third should be assigned to 1 when it is defined. When it is returned later, it will return 1 for the first time or the second time
        if (2 == n || 1 == n) {
            return 1;
        }
        
        int first = 1;
        int second = 1;
        int third = 0;// The third number is initialized to 0
        
        // It should be understood here that the third number needs to be iterated once, and so on
        while (n > 2) {
            third = first + second;
            first = second;
            second = third;
            n--;
        }
        return third;
    }
}
//LeetCode version
public class Solution {
    public int fib(int n) {
        if (0 == n) {
            return 0;
        }
        //The following if statement can be omitted on the premise that the value of third should be assigned to 1 when it is defined, and 1 will be returned for the first time or the second time when it is returned
        if (2 == n || 1 == n) {
            return 1;
        }
        
        int first = 1;
        int second = 1;
        int third = 0;// The third number is initialized to 0
        
        // It should be understood here that the third number needs to be iterated once, and so on
        while (n > 2) {
            third = first + second;
            //It is time-consuming to calculate the remainder. You can subtract 1000000007
            if (third >= 1000000007) {
                third -= 1000000007;
            }
            first = second;
            second = third;
            n--;
        }
        return third;
    }
}

Recursive code implementation (not recommended, do not write such code in the interview!)

class Solution {
    public int Fibonacci(int n) {
        if (0 == n) {
            return 0;
        }
        if (n <= 2) {
            return 1;
        }
        return Fibonacci(n - 2) + Fibonacci(n - 1);
    }
}

Recursion + no double counting (the recommended writing method is Microsoft's interview question)

//NowCoder version
import java.util.HashMap;
import java.util.Map;

public class Solution {
    private Map<Integer, Integer> filter = new HashMap<>();
    public int Fibonacci(int n) {
        if (n == 0 || n == 1) {
            return n;
        }
        
        int ppre = 0;// n-2
        if (filter.containsKey(n - 2)) { // eureka
            ppre = filter.get(n - 2);
        }else { // If you don't find it, calculate it yourself and add it
            ppre = Fibonacci(n - 2);
            filter.put(n-2, ppre);
        }
        
        int pre = 0;// n-1
        if (filter.containsKey(n - 1)) { // eureka
            pre = filter.get(n - 1);
        }else { // If you don't find it, calculate it yourself and add it
            pre = Fibonacci(n - 1);
            filter.put(n-1, pre);
        }
        return ppre + pre;
    }
}
//LeetCode version
import java.util.HashMap;
import java.util.Map;

public class Solution {
    private Map<Integer, Integer> filter = new HashMap<>();
    public int fib(int n) {
        if (n == 0 || n == 1) {
            return n;
        }
        
        int ppre = 0;// n-2
        if (filter.containsKey(n - 2)) { // eureka
            ppre = filter.get(n - 2);
        }else { // If you don't find it, calculate it yourself and add it
            ppre = fib(n - 2);
            filter.put(n-2, ppre);
        }
        
        int pre = 0;// n-1
        if (filter.containsKey(n - 1)) { // eureka
            pre = filter.get(n - 1);
        }else { // If you don't find it, calculate it yourself and add it
            pre = fib(n - 1);
            filter.put(n-1, pre);
        }
        int result = ppre + pre;
        if (result >= 1000000007) {
            result -= 1000000007;
        }
        return result;
    }
}

Thank you

Well, if the boss who pays attention to me may find out,

The article I wrote about brushing questions is from simple to difficult.

Now is just the beginning, that is, simple algorithms are used,

And this algorithm will be more and more difficult. Now it will be interspersed with some algorithm ideas: dynamic programming and backtracking!

In fact, everyone has seen the Fibonacci series, so it's boring for me to explain too many redundant things,

Therefore, I will let you understand the intuitive harm caused by space complexity and time and space consumption through this question!

Thank you again for your attention. Your support is my motivation!

Topics: Algorithm leetcode