2020-01-07

What is recursion:

Recursively, by definition, it refers to a function calls itself directly or indirectly, then there is recursion.

For example, one method to achieve the famous Feibolaqi number of columns:

```
1 public static int f(int n){
2
3 if(n == 1 || n == 2) return 1;
4
5 return f(n-1) + f(n-2);
6
7 }
```

In this example, the case of n greater than 2, we directly call itself recursively f solve this problem.

To think from the bottom of the case, in fact, related to the function of the computer pressed into the stack, and then pop out, so you want to use the extra space and time, so when not enough sophisticated algorithms related to the design, may bring additional expenses.

In fact, the mathematical nature of this algorithm is not a mystery, it is an ordinary mathematical induction: In order to solve the problem p (n), first solve the base case p (1), and then assume that p (n-1) has been completed in this condition next, if the solution of p (n), then this problem is solvable. (High school when we learn, is often used to demonstrate some of the problems, here it needs to move to a specific program to solve the problem, a slight difference)

Its mathematical essence seems difficult, however, when the actual programming, recursive thinking of actually " **counterintuitive** " (English is counter-intuitive), want a clear understanding of recursive functions step by step exactly what to do, even for very experienced programmers, it is very difficult. This is the kind of problem has been brought about mainly due to the recursive troubled for beginners.

If posture is not level, it would have to re-learn a. Reference [1] to say, when to understand recursion, you only need "

to understand each function can do, and I believe they can be completed" on it, the more modular dismantling is also a thing, understanding only need to reach "the section to complete the function xx "can, in fact, is not conducive to excessive dismantling program.

Based on this idea, we can introduce the so-called **"recursive three elements"** to think about the problems associated recursion. [2] (in relevant courses seen in the first nine chapters of the algorithm back to this argument, as the course itself, we matter of opinion)

Recursive three elements:

The definition of recursive: recursive function accepts what parameters, return what value, what does it mean. When the function calls itself directly or indirectly, when it happened recursion.

In short, it is because in the programming process, repeated use of this function, so this function should be strong reusability, general abstracted from the problem of solving the more general paradigm.

Recursive disassembly: recursion must make every scale of the problem becomes smaller.

For example, the number of columns in question Feibolaqi, we approach every step forward two steps at least some of the problems; In a related divide and conquer recursive design, the problem can often be broken down into two symmetrical portions of left and right, before dismantling , and then integrated the results were compared, or other operations.

Export recursive: recursive must have a clear end condition.

If the front is in the "delivery", then this step is to determine when to "go." If the delivery does not go a long time, it is rather "a glass of liquor at home thousands of miles, Le Yan then not go without a meter" flavor, and for the computer, the end result is naturally out of memory.

When programming, you need to pay attention to a given limit conditions for the function return value.

LeetCode 206 Reverse Linked List：

Title It will be understood that a linear list to which the inverted data, if the original is 1-> 2-> 3-> 4-> 5-> null, after completion of the inversion becomes 5-> 4-> 3 -> 2-> 1-> null. (Null is a null pointer, on behalf of the end of the list)

当然，本题自然也可以不用递归，直接使用迭代法(iterative)来解决，对于每一个节点，都保存其前驱(pre)以及后继(next)两个节点，不断进行原地(in-place)逆序即可。

此处还是以递归法来说明所谓“递归三要素”的理解应用：

对于这样一个链表，实际上用于保存它的方法是很简单的，它只保存了一个头节点，而每一个节点定义如下：

class ListNode{ int data; Node next; }

每一个节点只保存了自己的数据（此处是int）以及下一个节点的引用（或者说是地址，但是java没有指针，所以其实是下一个节点的引用）。

因此，这个问题天然地具有一种类似于数学上自同构(auto-morphism)的感觉，也就是问题可以被分解为对于每一个节点进行处理。

1.递归的定义：我们可以试着定义一个递归函数，它只处理一个给定节点，返回的是已经被处理好的链表的第一个节点。（比如说，对于1-2-3-4-5，如果输入一个3，返回的是5，对应的其实就是5-4这样一个被处理好的部分，随后将3再接到5-4之后，形成1-2-3以及5-4-3的情况）

2.递归的拆解：由于我们一开始只知道头节点head，所以比较合理的递归/前进方式是，每次输入一个head.next，也就是向后一次遍历一个引用，这也是合理的，因为从数据结构上来看，我们也只能作这样的访问。

3.递归的出口：到什么情况我们可以返回一个处理好的链表呢？其实这时对应的往往都是基础/平凡(trivial)的情况。对于本题，就是返回空指针、单个节点的情况（因为这样的情况不需要再反转了）。

由此我们可以给出代码：

1 // 递归的定义：下面的函数返回的是，将给定节点之后（包括这一节点）所有的节点反转之后的链表的头节点 2 // 输入：一个给定的节点 3 // 输出：包含本节点在内的反转链表的头节点 4 public ListNode reverseList(ListNode head){ 5 // 递归的出口：当是空指针或者单个节点时，返回其本身 6 if(head == null || head.next == null) return head; 7 8 // 递归的拆解：一个新的反转链表 = 当前节点之后的反转链表 + 将当前节点移动到已有的反转链表之后 9 ListNode next = reverseList(head.next); 10 head.next.next = head; // 注意，在修改head.next之前，head.next指向的依旧是原来的后续节点 11 head.next = null; 12 return next; // 返回新的反转链表 13 }

应该说，这个代码基本体现出了递归的三要素，在之后的练习中，也应该多思考递归函数的设计，而不是凑对了、看懂了就草草带过去，相关的设计思想往往就被遗漏了。

对于这一话题，下一步的计划：

1.练习更多、难度更大的题目

2.阅读一些算法教材，从更底层和本质的角度思考递归问题

Reference: