Stack and Depth First Search (DFS)

Keywords: github Android

Like BFS, Depth First Search (DFS) is another important algorithm for traversing/searching trees/graphs.It can also be used in more abstract scenarios.

As mentioned in Tree traversal, we can use DFS to traverse in the first order, in the middle order and after order.There is a common feature in these three traversal orders: we never go back until we reach the deepest node.

This is also the biggest difference between DFS and BFS, which will never be explored in depth unless it has accessed all the nodes at the current level.

Template

Recursive Template

There are two ways to implement DFS.The first method is recursion:

```boolean DFS(Node cur, Node target, Set<Node> visited) {
return true if cur is target;
for (next : each neighbor of cur) {
if (next is not in visited) {
return true if DFS(next, target, visited) == true;
}
}
return false;
}
```

When we implement DFS recursively, it seems that we don't need to use any stacks.But in fact, we use an implicit stack provided by the system, also known as a Call Stack.

Explicit Stack Template

The advantage of a recursive solution is that it is easier to implement.However, there is a big disadvantage: if the recursion depth is too high, you will suffer from a stack overflow.In this case, you may want to use BFS or use an explicit stack to implement DFS.

```boolean DFS(int root, int target) {
Set<Node> visited;
Stack<Node> s;
while (s is not empty) {
Node cur = the top element in s;
return true if cur is target;
for (Node next : the neighbors of cur) {
if (next is not in visited) {
}
}
remove cur from s;
}
return false;
}
```

Example

1. Number of islands

• Difficulty: Medium

Title Description

Given a two-dimensional grid of'1'(land) and'0' (water), the number of islands is calculated.An island is surrounded by water and connected horizontally or vertically by adjacent land.You can assume that all four edges of the grid are surrounded by water.

Example 1:

Input:
11110
11010
11000
00000
Output: 1

Example 2:

Input:
11000
11000
00100
00011
Output: 3

Ideas and implementation of problem solving

The author was at This article Shows how to use BFS to solve this problem. In fact, it is simpler to use DFS because it also requires a queue to maintain hierarchical information searched during breadth-first search.

Use DFS to solve the following problems:

```public class B200NumIslands {

public int numIslands(char[][] grid) {
int nr = grid.length;
if (nr == 0) return 0;
int nc = grid[0].length;
if (nc == 0) return 0;

int result = 0;

for (int r = 0; r < nr; r++) {
for (int c = 0; c < nc; c++) {
if (grid[r][c] == '1') {
result++;
dfs(grid, r, c);
}
}
}

return result;
}

private void dfs(char[][] grid, int r, int c) {
int nr = grid.length;
int nc = grid[0].length;

// Exclude cases outside the boundary
if (r >= nr || c >= nc || r < 0 || c < 0) return;
// Exclude cases where the specified location is'0'outside the boundary
if (grid[r][c] == '0') return;

// The location is an island, marked as explored
grid[r][c] = '0';

dfs(grid, r - 1, c);  // top
dfs(grid, r + 1, c);  // bottom
dfs(grid, r, c - 1);  // left
dfs(grid, r, c + 1);  // right
}
}
```

2. Clone Map

• Difficulty: Medium

Title Description

To give you a reference to a node in an undirected connectivity graph, return a deep copy (clone) of the graph.

Each node in the graph contains its value val (int) and a list of its neighbors (list[Node]).

```class Node {
public int val;
public List<Node> neighbors;
}
```

More detailed Title Description reference Here :
https://leetcode-cn.com/problems/clone-graph/

Ideas and implementation of problem solving

The title is rather difficult to understand. It should be noted that:

1. Because it is a deep copy, all nodes need to be instantiated with new, that is, each node in the graph needs to be traversed, so the solution emerges, using either DFS or BFS;
2. Mark each replicated node to avoid stack overflow due to an infinite loop.

The code implemented with DFS is as follows:

```class Solution {
public Node cloneGraph(Node node) {
HashMap<Node,Node> map = new HashMap<>();
return dfs(node, map);
}

private Node dfs(Node root, HashMap<Node,Node> map) {
if (root == null) return null;
if (map.containsKey(root)) return map.get(root);

Node clone = new Node(root.val, new ArrayList());
map.put(root, clone);
for (Node nei: root.neighbors) {
}
return clone;
}
}
```

3. Goals and objectives

• Difficulty: Medium

Title Description

Given a non-negative integer array, a1, a2,..., an, and a target number, S.Now you have two symbols + and -.For any integer in the array, you can select a symbol from + or - to add to the front.

Returns the number of methods that can make the final array and the target S add symbols.

Example 1:

```Input: nums: [1, 1, 1, 1], S: 3
Output: 5
Explanation:

>-1+1+1+1+1 = 3
+1-1+1+1+1 = 3
+1+1-1+1+1 = 3
+1+1+1-1+1 = 3
+1+1+1+1-1 = 3

There are five ways to achieve a final goal of 3.
```

Be careful:

1. The array is not empty and will not exceed 20 in length.
2. The sum of the initial arrays will not exceed 1000.
3. Ensure that the final result returned can be saved as a 32-bit integer.

Ideas and implementation of problem solving

To tell the truth, this question did not expect to be solved by DFS violence, or experience is too little. Violent solutions to this question are completely possible and will not time out, because the title says that the length of the array can not exceed 20, 20 numbers in a sequence, and 2^20 combinations in a combination way if it dies:

```public class Solution {

int count = 0;

public int findTargetSumWays(int[] nums, int S) {
dfs(nums, 0, 0, S);
return count;
}

private void dfs(int[] nums, int index, int sum, int S) {
if (index == nums.length) {
if (sum == S) count++;
} else {
dfs(nums, index + 1, sum + nums[index], S);
dfs(nums, index + 1, sum - nums[index], S);
}
}
}
```

4. Middle-order traversal of binary trees

• Difficulty: Medium

Title Description

Given a binary tree, return its median traversal.

Advanced: Recursive algorithm is very simple, can you do it through an iterative algorithm?

Ideas and implementation of problem solving

Binary tree correlation is really a very interesting arithmetic point of knowledge (because this topic is very representative, I think the highest probability of an interview is 2333...).In the future, the author will explore this knowledge point in more detail, and this paper lists two solutions.

1. Recursive method

```public class Solution {

// 1. Recursive method
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> list = new ArrayList<>();
dfs(root, list);
return list;
}

private void dfs(TreeNode node, List<Integer> list) {
if (node == null) return;

// Mid-order traversal: left, middle and right
if (node.left != null)
dfs(node.left, list);

if (node.right != null)
dfs(node.right, list);
}
}
```

2. Use stack

```public class Solution {

// 2. Use stack
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> list = new ArrayList<>();
Stack<TreeNode> stack = new Stack<>();

TreeNode curr = root;
while (!stack.isEmpty() || curr != null) {
while (curr != null) {
stack.push(curr);
curr = curr.left;
}
curr = stack.pop();
curr = curr.right;
}
return list;
}
}
```

Reference & Thank you

Most of the article is excerpted from LeetCode, Overview of Stack and Depth First Search:

• https://leetcode-cn.com/explore/learn/card/queue-stack/219/stack-and-dfs/

Example:

• https://leetcode-cn.com/problems/number-of-islands
• https://leetcode-cn.com/problems/clone-graph/
• https://leetcode-cn.com/problems/target-sum/
• https://leetcode-cn.com/problems/binary-tree-inorder-traversal/