本文共 7410 字,大约阅读时间需要 24 分钟。
leetcode dfs
Have you ever solved a real-life maze? The approach that most of us take while solving a maze is that we follow a path until we reach a dead end, and then backtrack and retrace our steps to find another possible path.
您是否解决了现实生活中的迷宫? 我们大多数人在解决迷宫时采取的方法是:沿着一条路直到到达死胡同,然后回溯并追溯我们的步骤以找到另一条可能的路。
This is exactly the analogy of Depth First Search (DFS). It's a popular graph traversal algorithm that starts at the root node, and travels as far as it can down a given branch, then backtracks until it finds another unexplored path to explore. This approach is continued until all the nodes of the graph have been visited.
这正是深度优先搜索(DFS)的类比。 这是一种流行的图形遍历算法,从根节点开始,一直沿给定分支向下传播,然后回溯直到找到另一条未探索的路径。 继续进行此方法,直到访问了图的所有节点为止。
In today’s tutorial, we are going to discover a DFS pattern that will be used to solve some of the important tree and graph questions for your next Tech Giant Interview! We will solve some Medium and Hard Leetcode problems using the same common technique.
在今天的教程中,我们将发现一种DFS模式,该模式将用于解决您下一次Tech Giant采访中的一些重要的树形图问题! 我们将使用相同的通用技术解决一些中度和硬性Leetcode问题。
So, let’s get started, shall we?
所以,让我们开始吧?
Since DFS has a recursive nature, it can be implemented using a stack.
由于DFS具有递归性质,因此可以使用堆栈来实现。
DFS Magic Spell:
DFS魔法:
In general, there are 3 basic DFS traversals for binary trees:
通常,对二进制树有3种基本的DFS遍历:
Pre Order: Root, Left, Right OR Root, Right, Left
预购:根,左,右或根,右,左
Post Order: Left, Right, Root OR Right, Left, Root
发布顺序:左,右,根或右,左,根
In order: Left, Root, Right OR Right, Root, Left
顺序:左,根,右或右,根,左
To solve this question all we need to do is simply recall our magic spell. Let's understand the simulation really well since this is the basic template we will be using to solve the rest of the problems.
要解决这个问题,我们要做的就是简单地回忆起我们的魔咒。 让我们很好地理解模拟,因为这是我们将用来解决其余问题的基本模板 。
At first, we push the root node into the stack. While the stack is not empty, we pop it, and push its right and left child into the stack.
首先,我们将根节点推入堆栈。 当堆栈不为空时,我们将其弹出,然后将其左右子项推入堆栈。
As we pop the root node, we immediately put it into our result list. Thus, the first element in the result list is the root (hence the name, Pre-order). The next element to be popped from the stack will be the top element of the stack right now: the left child of root node. The process is continued in a similar manner until the whole graph has been traversed and all the node values of the binary tree enter into the resulting list.
当我们弹出根节点时,我们立即将其放入结果列表。 因此,结果列表中的第一个元素是根(因此,其名称为Pre-order)。 从堆栈中弹出的下一个元素将是当前堆栈的顶部元素:根节点的左子节点。 以相似的方式继续该过程,直到遍历了整个图并且二叉树的所有节点值都进入结果列表为止。
Pre-order traversal is root-left-right, and post-order is right-left-root. This means post order traversal is exactly the reverse of pre-order traversal.
顺序遍历是root-left-right ,而顺序遍历是right-left-root 。 这意味着后订单遍历与前订单遍历完全相反。
So one solution that might come to mind right now is simply reversing the resulting array of pre-order traversal. But think about it – that would cost O(n) time complexity to reverse it.
因此,现在可能想到的一种解决方案就是简单地逆转最终的遍历结果数组。 但是考虑一下–反转它会花费O(n)时间复杂度。
A smarter solution is to copy and paste the exact code of the pre-order traversal, but put the result at the top of the linked list (index 0) at each iteration. It takes constant time to add an element to the head of a linked list. Cool, right?
一个更聪明的解决方案是复制并粘贴预遍历的确切代码,但是在每次迭代时将结果放在链接列表的顶部(索引0)。 向链接列表的开头添加元素需要花费固定的时间。 酷吧?
Our approach to solve this problem is similar to the previous problems. But here, we will visit everything on the left side of a node, print the node, and then visit everything on the right side of the node.
我们解决此问题的方法与先前的问题类似。 但是在这里,我们将访问节点左侧的所有内容,打印该节点,然后访问该节点右侧的所有内容。
Our approach here is to create a variable called ans that stores the number of connected components.
我们这里的方法是创建一个名为ans的变量,该变量存储已连接组件的数量。
First, we will initialize all vertices as unvisited. We will start from a node, and while carrying out DFS on that node (of course, using our magic spell), it will mark all the nodes connected to it as visited. The value of ans will be incremented by 1.
首先,我们将所有顶点初始化为未访问。 我们将从一个节点开始,并且在该节点上执行DFS时(当然,使用我们的魔术咒语),它将把与其连接的所有节点标记为已访问。 ans的值将增加1。
import java.util.ArrayList;import java.util.List;import java.util.Stack;public class NumberOfConnectedComponents { public static void main(String[] args){ int[][] edge = { {0,1}, {1,2},{3,4}}; int n = 5; System.out.println(connectedcount(n, edge)); } public static int connectedcount(int n, int[][] edges) { boolean[] visited = new boolean[n]; List[] adj = new List[n]; for(int i=0; i(); } // create the adjacency list for(int[] e: edges){ int from = e[0]; int to = e[1]; adj[from].add(to); adj[to].add(from); } Stack stack = new Stack<>(); int ans = 0; // ans = count of how many times DFS is carried out // this for loop through the entire graph for(int i = 0; i < n; i++){ // if a node is not visited if(!visited[i]){ ans++; //push it in the stack stack.push(i); while(!stack.empty()) { int current = stack.peek(); stack.pop(); //pop the node visited[current] = true; // mark the node as visited List list1 = adj[current]; // push the connected components of the current node into stack for (int neighbours:list1) { if (!visited[neighbours]) { stack.push(neighbours); } } } } } return ans; }}
This falls under a general category of problems where we have to find the number of connected components, but the details are a bit tweaked.
这属于一般问题类别,我们必须找到已连接组件的数量,但细节有所调整。
Instinctually, you might think that once we find a “1” we initiate a new component. We do a DFS from that cell in all 4 directions (up, down, right, left) and reach all 1’s connected to that cell. All these 1's connected to each other belong to the same group, and thus, our value of count is incremented by 1. We mark these cells of 1's as visited and move on to count other connected components.
本能地,您可能会认为,一旦找到“ 1”,便会启动一个新组件。 我们在该单元的所有4个方向(上,下,右,左)上执行DFS,并达到与该单元相连的所有1。 所有这些相互连接的1属于同一组,因此,我们的count值加1。我们将1的这些单元格标记为已访问,然后继续对其他连接的组件进行计数。
This also follows the same concept as finding the number of connected components. In this question, we have an NxN matrix but only N friends in total. Edges are directly given via the cells so we have to traverse a row to get the neighbors for a specific "friend".
这也遵循与查找已连接组件数相同的概念。 在这个问题中,我们有一个NxN矩阵,但总共只有N个朋友。 边缘是直接通过单元格给出的,因此我们必须遍历一行以获取特定“朋友”的邻居。
Notice that here, we use the same stack pattern as our previous problems.
请注意,在这里,我们使用与先前问题相同的堆栈模式。
That's all for today! I hope this has helped you understand DFS better and that you have enjoyed the tutorial. Please recommend this post if you think it may be useful for someone else!
今天就这些! 我希望这可以帮助您更好地了解DFS,并希望您喜欢本教程。 如果您认为此帖子可能对其他人有用,请推荐此帖子!
翻译自:
leetcode dfs
转载地址:http://nfuzd.baihongyu.com/