递归的核心是什么_递归的六种核心模式

本文探讨了递归的本质,并从原文中提炼出递归的六种核心模式,帮助读者深入理解递归在编程中的应用,尤其在Python、Java和Linux环境下,递归算法的重要性不言而喻。
摘要由CSDN通过智能技术生成

递归的核心是什么

Recursion made easy by applying one of these six patterns onto every question.

通过将这六个模式之一应用于每个问题,可以轻松实现递归。

Recursion, you may be slightly uncomfortable just by hearing the term. One of the core reasons people find recursion so tricky is that they don’t have an exact model of interpreting recursion as an approach.

递归时,仅听一听术语可能会使您感到有些不适。 人们发现递归如此棘手的核心原因之一是,他们没有将递归解释为一种方法的确切模型。

People solve various recursive problems and see different approaches to using it, but still don’t feel confident about using it. It’s just because every situation is entirely different that it makes it hard to figure out what’s going on.

人们解决了各种递归问题,并看到了使用它的不同方法,但是仍然对使用它没有信心。 只是因为每种情况都完全不同,所以很难弄清发生了什么。

This article will go through 6 recursive core patterns that may categorize all-recursive problems into one of them. You can apply them to almost any recursive questions.

本文将介绍6种递归核心模式,这些模式可以将所有递归问题归为其中之一。 您可以将它们应用于几乎所有递归问题。

These six patterns are — Iteration, Subproblems, Selection, Ordering, Divide & Conquer, and Depth First Search.

这六个模式是-迭代,子问题,选择,排序,分而治之深度优先搜索。

迭代 (Iteration)

As you may know, any problem that can be solved using loops can also be solved using recursion in place of it and vice-versa. It may not come handy often, but can be useful once in a while. We can use this pattern when we refer back to the items we’ve looped through previously.

如您所知,使用循环可以解决的任何问题也可以使用递归来解决,反之亦然。 它可能不会经常派上用场,但有时会有用。 当我们返回到之前遍历的项目时,可以使用此模式。

For example, if we want to print a linked list in reverse order.

例如,如果我们要以相反的顺序打印链表。

void printReverse(Node n) {
if (n == null) return;
printReverse(n.next);
print(n.val);
}

There are a lot of approaches we can take to print a linked list in reverse order, but recursion does it in a very concise way.

我们可以采用许多方法以相反的顺序打印链表,但是递归以一种非常简洁的方式做到了。

子问题 (Subproblems)

One of the core reasons why recursion is used is that it lets us break down the problems into its subproblems. If you look closely, you could use this to solve any recursive problem, but we are going through the other patterns because they get much more specific about helping you do that.

使用递归的核心原因之一是它使我们可以将问题分解为子问题。 如果您仔细观察,可以使用它来解决任何递归问题,但是我们正在研究其他模式,因为它们在帮助您执行操作方面变得更加具体。

You must have come across problems that themselves are speaking to be broken down into subproblems. One such example is the Fibonacci problem. In this case, even the mathematical definition of the Fibonacci sequence is recursive in nature.

您一定遇到了自己正在分解为子问题的问题。 斐波那契问题就是一个这样的例子。 在这种情况下,即使斐波那契数列的数学定义在本质上也是递归的。

Another problem that frequently comes up is the Towers of Hanoi problem. In problems like this, you have to come up with the decision of breaking down the problem into its subproblems.

经常出现的另一个问题是河内塔问题。 对于此类问题,您必须做出将问题分解为子问题的决定。

选拔 (Selection)

It is the most common pattern to come up in Recursion and Dynamic Programming. In this pattern, we are going through all the possible solutions and selecting the ones which match our condition.

这是递归和动态编程中最常见的模式。 在这种模式下,我们将研究所有可能的解决方案,然后选择与我们的条件匹配的解决方案。

Let’s consider the example of the 0–1 Knapsack Problem. In this problem, we have a series of weights associated with some value. We have to figure out the maximum value that we can achieve under some specific weight. This problem is a classic dynamic programming problem, but let’s look at it from a recursive approach.

让我们考虑0-1背包问题的例子。 在此问题中,我们具有一系列与某个值相关的权重。 我们必须找出在特定重量下可以达到的最大值。 这个问题是经典的动态编程问题,但让我们从递归方法来看一下。

The brute force solution to this problem is to generate all the possible combinations and choose the most optimal answer from it.

解决该问题的暴力解决方案是生成所有可能的组合,并从中选择最佳答案。

Figuring out all the combinations is the core of selection problems. We decide to include/exclude each item from our possible variety of solutions.

找出所有组合是选择问题的核心。 我们决定在可能的各种解决方案中包括/排除每个项目。

List<List<Integer>> combinations(int[] n) {
List<List<Integer>> results = new LinkedList();
combinations(n, 0, results, new LinkedList<Integer>());
return results;
}

void combinations(int[] n, int i, List<List<Integer>> results, List<Integer> path) {
if (i == n.length) {
results.add(path);
return;
}

List<Integer> pathWithCurrent = new LinkedList(path);
pathWithCurrent.add(n[i]);

// Find all the combinations that exclude the current item
combinations(n, i+1, results, path);

// Find all the combinations that include the current item
combinations(n, i+1, results, pathWithCurrent);
}

This pattern comes up so frequently in so many different forms.

这种模式经常以多种不同的形式出现。

订购方式 (Ordering)

This pattern is the permutation to Selections’ combination. We’re focused on the case where we are concerned about the different ordering of the values. Figure out all the permutations of a given set of elements is the most straightforward problem.

此模式是对Selections组合的排列。 我们专注于关注值的不同顺序的情况。 找出给定元素集的所有排列是最直接的问题。

Some examples are Bogosort (generate all the permutations and then determining which is sorted), or determining all palindromes from a set of characters.

例如Bogosort(生成所有排列,然后确定排序的对象),或从一组字符确定所有回文。

List<List<Integer>> permutations(Set<Integer> n) {
List<List<Integer>> results = new LinkedList();
permutations(n, results, new LinkedList<Integer>());
return results;
}

void permutations(Set<Integer> n, List<List<Integer>> results, List<Integer> path) {
if (n.isEmpty()) {
results.add(path);
return;
}

for (int i : n) {
// For now ignore concurrent modification issue
n.remove(i);
List<Integer> pathWithCurrent = new LinkedList(path);
pathWithCurrent.add(i);
permutations(n, results, pathWithCurrent);
n.add(i);
}
}

By combining the selection and ordering pattern, you can cover a great number of recursive questions.

通过组合选择和排序模式,您可以涵盖大量的递归问题。

分而治之 (Divide and Conquer)

In divide and conquer, we split the space into half, solve each help separately, and then combine them to get the result. Divide and conquer is the core of many algorithms such as merge sort, depth-first search, and binary search.

在分而治之中,我们将空间分成两半,分别解决每个帮助,然后将它们组合以获得结果。 分而治之是许多算法的核心,例如合并排序,深度优先搜索和二进制搜索。

This technique is an approach to tree and sorting/searching problems where we split the problem space and then recombine the results to get the final solution.

这种技术是一种对树进行树形和排序/搜索的方法,其中我们拆分问题空间,然后重新组合结果以获得最终解决方案。

The code to split a string into it’s every point:

将字符串拆分为每个点的代码:

List<String> parentheses(String s) {
if (s.length() == 1) {
List<String> result = new LinkedList<String>();
result.add(s);
return result;
}

List<String> results = new LinkedList<String>();

for (int i = 1; i < s.length(); i++) {
List<String> left = parentheses(s.substring(0, i));
List<String> right = parentheses(s.substring(i, s.length()));

for (String s1 : left) {
for (String s2 : right) {\
results.add("(" + s1 + s2 + ")");
}
}
}

return results;
}

In this example, we find different midpoints to split the string. For example, “abcd” becomes “(a)(bcd)”, “(ab)(cd)”, and “(abc)(d)”.

在此示例中,我们找到了不同的中点来分割字符串。 例如,“ abcd”变为“(a)(bcd)”,“(ab)(cd)”和“(abc)(d)”。

深度优先搜索 (Depth First Search)

DFS is the final pattern that our recursive functions can fall. It is also widely used because DFS (or BFS) is used almost whenever working with trees and graphs.

DFS是我们递归函数可能失败的最终模式。 它也被广泛使用,因为几乎在处理树和图形时都会使用DFS(或BFS)。

A critical thing with DFS is not limiting yourself to searching the nodes in a tree or graphs but also knowing how to find the path itself.

使用DFS的关键是,不仅要限制自己搜索树或图形中的节点,还要知道如何查找路径本身。

Here’s the code to find the path to a specific node in a tree:

这是用于找到树中特定节点的路径的代码:

List<Node> pathToNode(Node root, int val) {
if (root == null) return null;
if (root.value == val) {
List<Node> toReturn = new LinkedList<Node>();
toReturn.add(root);
return toReturn;
}

List<Node> left = pathToNode(root.left, val);
if (left != null) {
left.add(0, root);
return left;
}

List<Node> right = pathToNode(root.right, val);
if (right != null) {
right.add(0, root);
return right;
}

return null;
}

DFS is mostly used as a part of a larger problem; therefore, it is essential to understand the core of how DFS works.

DFS主要用作更大问题的一部分; 因此,必须了解DFS如何工作的核心。

With these six recursive patters, you can almost solve any recursive problem that you encounter. The key is to look for the above-specified patterns. If you find it, use it. Different things work for other people. You can use different patterns to solve the same problem. So, do what feels right for you.

使用这六个递归模式,您几乎可以解决遇到的任何递归问题。 关键是寻找上述指定的模式。 如果找到它,请使用它。 不同的事情对其他人有用。 您可以使用不同的模式来解决相同的问题。 因此,做适合自己的事情。

Source —

资源 -

https://www.byte-by-byte.com/

https://www.byte-by-byte.com/

https://www.youtube.com/channel/UCWSYAntBbdd2SLYUqPIxo0w

https://www.youtube.com/channel/UCWSYAntBbdd2SLYUqPIxo0w

翻译自: https://medium.com/swlh/the-six-core-patterns-of-recursion-b1b4ea878f27

递归的核心是什么

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值