This is what the interviewer wants to hear: explain the correct way to open the recursion question

Time:2021-5-5

preface

Recursion, is a very important concept, but also very like the interview test. Because it can not only examine a programmer’s algorithmic skills, but also a good examination of the algorithmTime space complexityThe understanding and analysis of.

This article only talks about one problem, which is also the first problem of recursion in almost all algorithm books, but we strive to talk about flowers. Here we share four different angles, so that you can have different harvest.

  • Spatiotemporal complexityDetailed analysis of
  • Identify andsimplifyIn recursive processrepeatoperation
  • Wolf in sheep’s clothing
  • Proper flaunting helped me get my first job

Algorithm thinking

As we all know, a method calling itself is recursion. That’s right, but this is only the superficial understanding of recursion.

So recursiveessenceWhat is it?

Answer: < span style=“ color:blue “> the essence of recursion is that we can decompose a big problem into smaller problems, and then we can use the solutions of small problems to construct the solutions of big problems</ span>

How to get the solution of the small problem?

A: it’s constructed by the deconstruction of a smaller problem. When it’s too small, it’s time for the zero problem, that is, base case.

This is what the interviewer wants to hear: explain the correct way to open the recursion question

So let’s summarize the three steps of recursion

Base case: it’s the zero problem of recursion, and it’s also the end point of recursion. When you get to the smallest problem, you can give the result directly, and you don’t have to go any further. Otherwise, it will become a dead loop;

Dismantling: the problem of each layer should be smaller than that of the previous layer. Only by continuously reducing the size of the problem, can we go from big to small to base case;

combinationWe need to know how to construct the solution of the big problem.

So for each recursion problem, we will analyze it according to these three steps, make these three problems clear, and the code will be easy to write.

Fibonacci sequence

Although this is a platitude, I believe what I share here will give you other gains.

Title Description

Fibonacci sequence is an Italian mathematician. He has no time to study the process of rabbit reproduction. After studying, he found that it can be written as a sequence: 1, 1, 2, 3, 5, 8, 13, 21… That is, each number is equal to the sum of its first two numbers. So I’ll give you the nth number and ask what f (n) is.

analysis

It is very simple to express by mathematical formula

$$f(n) = f(n-1) + f(n-2)$$

The code is also very simple, using the three steps we just summarized:

  • base case: f(0) = 0, f(1) = 1.
  • Decomposition: F (n-1), f (n-2)
  • Combination: F (n) = f (n-1) + F (n-2)

So it’s written:

class Solution {
    public int fib(int N) {
        if (N == 0) {
            return 0;
        } else if (N == 1) {
            return 1;
        }
        return fib(N-1) + fib(N-2);
    }
}

But leetcode’s speed experience is only faster than 15% of the answer, because its time complexity is too high!

This is what the interviewer wants to hear: explain the correct way to open the recursion question

process analysis

That’s the first point I want to share, how to analyze the recursive process.

First, let’s draw this recursion tree. For example, let’s draw the recursion tree of F (5)

This is what the interviewer wants to hear: explain the correct way to open the recursion question

What is the actual implementation route?

First, follow the leftmost line all the way to the end: F (5) → f (4) → f (3) → f (2) → f (1). Finally, a base case can return f (1) = 1, then return to the f (2) layer, and then go down to f (0), then hit the bottom and bounce back to f (2), and get the result of F (2) = 1 + 0 = 1. Return this result to f (3), and then go to f (1), Get the result and then return to f (3) to get f (3) = left + right = 2, and then return the result

This approach is essentially driven by our computersVon Neumann systemAt presentA CPU and a core can only execute one instruction at a timeTherefore, f (3) and f (4) cannot be carried out together. It must be that f (4) is executed first (FIB (n-1) is put in front of this code), and then f (3) is executed

We can see the situation in the stack by debugging in the IDE: This is indeed the leftmost line to go first, with a total of five layers, and then go back up layer by layer.

This is what the interviewer wants to hear: explain the correct way to open the recursion question

Do not understand the small partner can watch the video to explain Oh ~

Time complexity analysis

How to evaluate an algorithm?

There are many solutions to many problems. After all, all roads lead to Rome. But how to evaluate the merits of each method, we generally use theBig O expressionTo measureTime and spaceComplexity.

Time complexity: with the growth of independent variables, the growth of time required.

Here, the big O represents an algorithmworst caseThis is what we are most concerned about. Otherwise, the system will be unable to hold when the Spring Festival rush tickets. Do you tell me that this algorithm is excellent?

Of course, there are other ways to measure time and space, such as

Theta: it’s about tight bound
Omega (n): This describes the best case. It’s meaningless

<span style=” color:blue “> this also gives us some inspiration, don’t say how good your performance is, it’s meaningless; The interview measures your level in the worst case; Don’t say that the interview didn’t show your real level, but it’s our real level.

What is the time complexity for this problem?

A: because we’ve gone through each node, we’re going toAll nodes add upIt’s the total time.

Here, what we do on each node is to add and sum, which is the operation of O (1), and the time of each node is the same

Total time = number of nodes * time of each node

That would be beggingNumber of nodesMy math problem:

When n = 5,

This is what the interviewer wants to hear: explain the correct way to open the recursion question

The top layer has one node,
Two on the second floor,
Four on the third floor,
Eight on the fourth floor,
There are 16 in the fifth layer. If it is filled, imagine it as a big tree:)

Let’s not care about this unfilled place. There must be so many nodes. But we have just mentioned the time complexity of big O expression. We are looking for worst case

Then the total number of nodes is:
1 + 2 + 4 + 8 + 16

This is the sum of an equal ratio sequence. Of course, you can use the mathematical formula, but there is another oneanticIt can help you quickly calculate:

<span style=” color:blue “> in fact, the total number of nodes in the previous layer will not exceed the number of nodes in the last layer. The total number of nodes is at most, that is, the number of nodes in the last layer * 2. In the time complexity of big O, the constant term does not matter, so the total time complexity is:

<span style=”color:blue”>

Number of nodes in the last layer: 2 ^ n

Spatial complexity analysis

The spatial complexity in general books refers to:

The amount of time the algorithm needs to occupy during its operationAllMemory space

But in the company we often use, is also the interview asked, refers to
Auxiliary space complexity

The amount of time required to run the algorithmadditionalSpace.

<span style=” color:blue “> give an example to illustrate the difference: for example, if the result allows you to output an array of length N, then the space of O (n) is not included in the space complexity of the algorithm, because this space can not run away, and it does not depend on your algorithm.

How to analyze the spatial complexity?

We just talked about the von Neumann system, and it’s easy to see from the picture, rightThe route on the far leftIt takes up the most space in the stack, and it’s constantly changingStack upIn other words, from 5 to 4 to 3 to 2, it is pressed to 1 until the base case returns. The space complexity occupied by each node is O (1), so the total space complexity is 0O(n).

I also mentioned in the above video, students who don’t understand look up at the video

optimization algorithm

Then we thought, why such a simple operation should have exponential time complexity? What makes time so big.

It’s not hard to see. It’s in this treeRecursion TreeThere are too many in the libraryDouble countingIt’s too late.

For example, an F (2) has been calculated three times here, and f (3) has been calculated two times, and it has to be recalculated every time. Isn’t that rightThe bear broke the stickIt’s really a bitter tear.

After finding out the reason, in order to solve this kind of repeated calculation, the method used by computers is actually the same as that used by human beingsTake notes

For many professions, such as doctors, lawyers, and our engineers, why is experience valuable as we get older? Because we have seen a lot and accumulated a lot, when we encounter similar problems next time, we can quickly give solutions. Even if we can’t solve them for a while, we can also avoid some blind trial and error. We willStanding at the height of the past and making continuous progressInstead of starting from scratch every time.

Back to the optimization algorithm, how does the computer take notes?

If we want to find f (n), we have to
Record the values of F (0) ~ f (n-1)
Then choose a suitable data structure to store.

It’s obvious here that we use an array to store:

Index 0 1 2 3 4 5
F(n) 0 1 1 2 3 5

With this kitchen sheet, we can get the results from the front to the back. In this way, each point is only calculated once, and can be written with a for loop. The code is also very simple.

class Solution {
    public int fib(int N) {
        if (N == 0) {
            return 0;
        }
        if (N== 1) {
            return 1;
        }
        int[] notes = new int[N+1];
        notes[0] = 0;
        notes[1] = 1;
        for(int i = 2; i <= N; i++) {
            notes[i] = notes[i-1] + notes[i-2];
        }
        return notes[N];
    }
}

This speed is 100% ~

This is what the interviewer wants to hear: explain the correct way to open the recursion question

But we can see that there should be room for optimization.

If you think about it, actually weDo you need to take so many notes? Do you need to keep your notes from kindergarten to primary school to junior high school to senior high school?

That’s actually the calculation of each itemIt only depends on the two items before itSo just keep these two.

Then we can use an array of length 2 to calculate, or just use two variables.

Update code:

class Solution {
    public int fib(int N) {
        int a = 0;
        int b = 1;
        if(N == 0) {
            return a;
        }
        if(N == 1) {
            return b;
        }
        for(int i = 2; i <= N; i++) {
            int tmp = a + b;
            a = b;
            b = tmp;
        }
        return b;
    }
}

So we optimize the space complexity toO(1)The time complexity is the same as array recordingO(n).

This method is actuallydynamic programming Dynamic ProgrammingThe code is very simple.

<span style=” color:blue “> let’s compare recurrence and DP:

RecursionFrom large to small, it decomposes layer by layer until the base case cannot be decomposed, and then it can be combined and returned;
DPIt’s growing up, taking good notes and making progress.

that isRecursion + Cache = DP

How to take notes and how to take notes efficiently are the difficulties of DP.

Some people say that DP is to trade space for time, but I don’t think so. This problem is a good example.

When solving problems recursively, we can see that the space is O (n) on the stack, but < span style=“ display:block; color:blue “> with DP, we can optimize the space to o (1), and DP can achieve the double optimization of time and space</ span>

In fact, Fibonacci sequence has many applications in real life.

For example, in our company and many large companies, each task should be given a score. One score means that it will take about one day to complete, and then the score is only 1, 2, 3, 5 and 8. (if there are tasks with a score greater than 8, you need to break down them into tasks with a score less than 8, so that you can complete them in two weeks.)
Because the task is never finished, and everyone’s time is limited, so every group meeting, pick out the most important task for everyone to do, and then everyone according to their available days to pick up the corresponding task.

Wolf in sheep’s clothing

Some students may think, this question is so simple, it’s all in 2020, will the interview test?

A:Really.

I just can’t give it to you in such a straightforward way.

For example, it’s very famousclimb stairsQuestion:

An n-step staircase can walk one or two floors at a time. How many ways are there.

Think about it this way

Standing in the current position, you can only come up from the previous layer or the first two layers, so f (n) = f (n-1) + F (n-2)

I was actually asked this question when I was interviewing. At that time, I was still writing python. In order to show off my skills, I also used lambda function:

f = lambda n: 1 if n in (1, 2) else f(n-1) + f(n-2)

Recursive writing time complexity is too high, so write a version for loop

def fib(n)
  a, b = 1, 1
  for i in range(n-1):
    a, b = b, a+b
  return a 

Then I wrote a caching method:

def cache(f):
    memo = {}
    def helper(x):
        if x not in memo:
            memo[x] = f(x)
        return memo[x]
    return helper
@cache
def fibR(n):
    if n==1 or n==2: return 1
    return fibR(n-1) + fibR(n-2)

<span style=” color:blue “> I also talked with the interviewer about tail recurrence:

Tail recursion: recursion is the last sentence of the whole method.

What’s so special about this one?

The characteristic of tail recursion is that we canIt’s easy to turn it into an iterative wayOf course, some intelligent compilers will automatically do it for us (not to say explicit conversion, but to run it in an iterative way at runtime. The actual space consumed is O (1))

So why?

Because there is no need for backtrack when it comes back, recursion here is the last step, and there is no need to go up one level to return the value.

def fib(n, a=0, b=1):
    if n==0: return a
      if n==1: return b
    return fib(n-1, b, a+b)

<span style=” color:blue “> in the end, I came up with my trump card: lambda and reduce

fibRe = lambda n: reduce(lambda x, n: [x[1], x[0]+x[1]], range(n), [0, 1])

After seeing the interviewer’s satisfied expression, I began to talk deeply

So, don’t think it’s simple. You can use seven or eight methods to solve the same problem. Analyze the advantages and disadvantages of each method, extend it to the place where you can extend it, and show your solid basic skills. This interview is actually an opportunity for you to show off. Only in this way can you cheat the interviewer

This is all the content of this article. I don’t know how you feel after reading it? Leave a message and tell me how you feel

This video has been made for a long time today. If you like this form, please join us

Click to see, encourage me!

It seems that I am very popular to write comments blindly!

Forward, love her, give her!

Also want to see more data structure and algorithm problems with me, rememberPay attention to meI’m Tian Xiaoqi. That’s the algorithm.

Recommended Today

Analysis of super comprehensive MySQL statement locking (Part 1)

A series of articles: Analysis of super comprehensive MySQL statement locking (Part 1) Analysis of super comprehensive MySQL statement locking (Part 2) Analysis of super comprehensive MySQL statement locking (Part 2) Preparation in advance Build a system to store heroes of the Three KingdomsheroTable: CREATE TABLE hero ( number INT, name VARCHAR(100), country varchar(100), PRIMARY […]