DFS:从勉强看懂到运用自如

恭喜发现宝藏!微信搜索公众号【TechGuide】关注更多新鲜好文和互联网大厂的笔经面经。
作者@TechGuide【全网同名】
点赞再看,养成习惯,您动动手指对原创作者意义非凡🤝

前言

在笔者大大小小笔试了五六场之后,似乎得到了一点规律,互联网大厂的笔试题集中在两大块,一是dp动态规划,另外一个就是dfs深度优先搜索(也包含回溯问题)了。之前笔试的时候,总是觉得面对这种类型的题目,即使勉强写出来了,也远远没有达到融会贯通的程度,很是苦恼。看了几十篇高赞高评论的总结对比文章后,并没有觉得有什么帮助,我总结了两个原因,第一个原因就是作者讲的太浅了,最然容易理解,却无法实际运用到更加复杂的场景中,另一个原因就是,很多别人得出的宝贵结论,你因为缺少自己的思考和大量题目的训练而无法感同身受,因而无法体会到其中的精妙之处。所以,我最后总结出的解决dfs的最好方法是我要打十个!!! 做 出 l e e t c o d e 问 题 中 d f s 专 项 下 面 的 所 有 题 目 ! 做出leetcode问题中dfs专项下面的所有题目! leetcodedfs
(咋感觉比打十个还猖狂。。orz)

正文

以下是关于dfs的所有中等难度题目,一共
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
给大家感受一下题量,剩下的就不粘了,完整版可以看这里。所以这也告诉我们,题目是千变万化的,只有具备解出dfs题目的能力才是关键。然鹅!!这里一共有90道左右,我。。。后悔了。。。但但是!!规律我一定要找到,总结给大家,前提是你能像我一样自己绞尽脑汁、花了大量时间在上面钻研,你才能有所感悟。

1. 路径和问题

(代码已详细注释,注释很细节,是引导思维的)

//Given a binary tree and a sum, find all root-to-leaf paths where each path's s
//um equals the given sum. 
//
// Note: A leaf is a node with no children. 
//
// Example: 
//
// Given the below binary tree and sum = 22, 
//
// 
//      5
//     / \
//    4   8
//   /   / \
//  11  13  4
// /  \    / \
//7    2  5   1
// 
//
// Return: 
//
// 
//[
//   [5,4,11,2],
//   [5,8,4,5]
//]


//leetcode submit region begin(Prohibit modification and deletion)
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
	//这里为什么写在方法外呢?这样可以作为一个类方法共同使用,简化代码。
    List<List<Integer>> res = new LinkedList<>();
    public List<List<Integer>> pathSum(TreeNode root, int sum) {
    	//为什么要重新写个函数呢?
    	//因为回溯的关键是有记忆的,除了栈,还有的就是参数传递,主函数的参数不适合递归。
        dfs(root,new LinkedList<Integer>(),sum);//也可以用ArrayList
        return res;
    }

    private void dfs(TreeNode node,LinkedList<Integer> temp,int target){
        if(node==null) {
            return;
        }
        temp.add(node.val);
        if(node.left==null && node.right==null && node.val == target) {
            res.add(new LinkedList<Integer>(temp));
        }
        //以上都是递归出口(判断条件),可以理解为dfs中我走到头了,
        //发现对或者不对,我标记之后,都要回退一步。
        //下面两句就是常规情况,发现还没到递归出口,我深入往前探进,
        //同时用栈存了我之前的位置,并用参数传递给下一步我已经存储的信息。
        dfs(node.left,temp,target-node.val);
        dfs(node.right,temp,target-node.val);
        //注意下面这句是带着上面递归出口共用的
        temp.removeLast();
    }
}
temp的变化过程(从上至下):
				5 
				5 4 
				5 4 11 
				5 4 11 7 //到这满了,下一个为null,到达叶子节点
				=============
				5 4 11 7 //有两次是因为两次打印了两次,和上一次可以只看作一次
				5 4 11 
				5 4 11 2 
				=============
				5 4 11 2 
				5 4 11 
				=============
				5 4 11 
				5 4 
				=============
				5 4 
				5 
				5 8 
				5 8 13 
				=============
				5 8 13 
				5 8 
				5 8 4 
				5 8 4 5 
				=============
				5 8 4 5 
				5 8 4 
				5 8 4 1 
				=============
				5 8 4 1 
				5 8 4 
				=============
				5 8 4 
				5 8 
				=============
				5 8 
				5 
				=============
				5  

2.打印二叉树为链表

//Given a binary tree, flatten it to a linked list in-place. 
//
// For example, given the following tree: 
//
// 
//    1
//   / \
//  2   5
// / \   \
//3   4   6
// 
//
// The flattened tree should look like: 
//
// 
//1
// \
//  2
//   \
//    3
//     \
//      4
//       \
//        5
//         \
//          6
// 



//leetcode submit region begin(Prohibit modification and deletion)
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    TreeNode pre = null;
    public void flatten(TreeNode root) {
        if(root==null) return; 
        flatten(root.right); //后序串接
        flatten(root.left);	//先一口气遍历到最靠右的叶子节点,再往回拼接
        root.right = pre;//以下三句,拼接串,此时的pre实际是上次弹栈之前保存的节点值。
        root.left = null;
        pre = root;
    }
}

3.二叉树打印层链表

//You are given a perfect binary tree where all leaves are on the same level, an
//d every parent has two children. The binary tree has the following definition: 
//
// 
//struct Node {
//  int val;
//  Node *left;
//  Node *right;
//  Node *next;
//}
// 
//
// Populate each next pointer to point to its next right node. If there is no ne
//xt right node, the next pointer should be set to NULL. 
//
// Initially, all next pointers are set to NULL. 
//
// 
//
// Follow up: 
//
// 
// You may only use constant extra space. 
// Recursive approach is fine, you may assume implicit stack space does not coun
//t as extra space for this problem. 
// 
//
// 
// Example 1: 
//
// 
//
// 
//Input: root = [1,2,3,4,5,6,7]
//Output: [1,#,2,3,#,4,5,6,7,#]
//Explanation: Given the above perfect binary tree (Figure A), your function sho
//uld populate each next pointer to point to its next right node, just like in Fig
//ure B. The serialized output is in level order as connected by the next pointers
//, with '#' signifying the end of each level.
// 
//
// 
// Constraints: 
//
// 
// The number of nodes in the given tree is less than 4096. 
// -1000 <= node.val <= 1000 

//leetcode submit region begin(Prohibit modification and deletion)
/*
// Definition for a Node.
class Node {
    public int val;
    public Node left;
    public Node right;
    public Node next;

    public Node() {}
    
    public Node(int _val) {
        val = _val;
    }

    public Node(int _val, Node _left, Node _right, Node _next) {
        val = _val;
        left = _left;
        right = _right;
        next = _next;
    }
};
*/

class Solution {
    public Node connect(Node root) {
        if(root==null) return null;
        dfs(root.left,root.right); //分出的原因同上
        return root;
    }

    private void dfs(Node n1, Node n2){
        if(n1==null) return;	//出口,针对不同情况都要连接,并判断是否到头
        n1.next = n2;			//左子树为空才返回,右子树为空还是可以被连上的
        dfs(n1.left,n1.right); //对于每个node来说,需要连接左右孩子有三种不同的情况
        dfs(n2.left,n2.right);
        dfs(n1.right,n2.left);
    }
}

4. 各路径解析数字和

(这一题和第一题类似,只是稍微变化一下,是练习的重要一步,套一遍当作复习,提高了信心,从这题开始也有了点手感)

//Given a binary tree containing digits from 0-9 only, each root-to-leaf path co
//uld represent a number. 
//
// An example is the root-to-leaf path 1->2->3 which represents the number 123. 
//
//
// Find the total sum of all root-to-leaf numbers. 
//
// Note: A leaf is a node with no children. 
//
// Example: 
//
// 
//Input: [1,2,3]
//    1
//   / \
//  2   3
//Output: 25
//Explanation:
//The root-to-leaf path 1->2 represents the number 12.
//The root-to-leaf path 1->3 represents the number 13.
//Therefore, sum = 12 + 13 = 25. 
//
// Example 2: 
//
// 
//Input: [4,9,0,5,1]
//    4
//   / \
//  9   0
// / \
//5   1
//Output: 1026
//Explanation:
//The root-to-leaf path 4->9->5 represents the number 495.
//The root-to-leaf path 4->9->1 represents the number 491.
//The root-to-leaf path 4->0 represents the number 40.
//Therefore, sum = 495 + 491 + 40 = 1026. 


//leetcode submit region begin(Prohibit modification and deletion)
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
import java.util.*;
import java.lang.*;
class Solution {
    List<StringBuilder> arr = new ArrayList<>();
    public int sumNumbers(TreeNode root) {
        dfs(root,new StringBuilder(""));
        int sum = 0;
        for(StringBuilder e:arr){
            sum+=Integer.parseInt(e.toString());
        }
        return sum;
    }
    private void dfs(TreeNode node, StringBuilder num){
        if(node==null) return;
        num.append(node.val);
        //唯一的变化就是这里出口条件变了一下,是不是慢慢有了套路的感觉?
        if(node.left==null && node.right==null){ 
            arr.add(new StringBuilder(num));
        }
        dfs(node.left,num);
        dfs(node.right,num);
        num = num.deleteCharAt(num.length()-1);
    }

}

5. 图的深拷贝

有时候做到这里,部分同学的畏难心理就发作了,关于图的题目都不做,实际上,关于图的算法在面试中也是有一定比例考察的,所以最好拿下几个比较经典的题目。这道题目表面上是图的题目,实际就是二叉树的变体而已(可以认为二叉树是一种特殊的图)。

//Given a reference of a node in a connected undirected graph. 
//
// Return a deep copy (clone) of the graph. 
//
// Each node in the graph contains a val (int) and a list (List[Node]) of its ne
//ighbors. 
//
// 
//class Node {
//    public int val;
//    public List<Node> neighbors;
//}
// 
//
// 
//
// Test case format: 
//
// For simplicity sake, each node's value is the same as the node's index (1-ind
//exed). For example, the first node with val = 1, the second node with val = 2, a
//nd so on. The graph is represented in the test case using an adjacency list. 
//
// Adjacency list is a collection of unordered lists used to represent a finite 
//graph. Each list describes the set of neighbors of a node in the graph. 
//
// The given node will always be the first node with val = 1. You must return th
//e copy of the given node as a reference to the cloned graph. 
//
// 
// Example 1: 
//
// 
//Input: adjList = [[2,4],[1,3],[2,4],[1,3]]
//Output: [[2,4],[1,3],[2,4],[1,3]]
//Explanation: There are 4 nodes in the graph.
//1st node (val = 1)'s neighbors are 2nd node (val = 2) and 4th node (val = 4).
//2nd node (val = 2)'s neighbors are 1st node (val = 1) and 3rd node (val = 3).
//3rd node (val = 3)'s neighbors are 2nd node (val = 2) and 4th node (val = 4).
//4th node (val = 4)'s neighbors are 1st node (val = 1) and 3rd node (val = 3).
// 
//
// Example 2: 
//
// 
//Input: adjList = [[]]
//Output: [[]]
//Explanation: Note that the input contains one empty list. The graph consists o
//f only one node with val = 1 and it does not have any neighbors.
// 
//
// Example 3: 
//
// 
//Input: adjList = []
//Output: []
//Explanation: This an empty graph, it does not have any nodes.
// 
//
// Example 4: 
//
// 
//Input: adjList = [[2],[1]]
//Output: [[2],[1]]
// 
//
// 
// Constraints: 
//
// 
// 1 <= Node.val <= 100 
// Node.val is unique for each node. 
// Number of Nodes will not exceed 100. 
// There is no repeated edges and no self-loops in the graph. 
// The Graph is connected and all nodes can be visited starting from the given n
//ode.

//leetcode submit region begin(Prohibit modification and deletion)
/*
// Definition for a Node.
class Node {
    public int val;
    public List<Node> neighbors;
    
    public Node() {
        val = 0;
        neighbors = new ArrayList<Node>();
    }
    
    public Node(int _val) {
        val = _val;
        neighbors = new ArrayList<Node>();
    }
    
    public Node(int _val, ArrayList<Node> _neighbors) {
        val = _val;
        neighbors = _neighbors;
    }
}
*/

class Solution {
    HashMap<Integer,Node> map = new HashMap<>();
    public Node cloneGraph(Node node) {
        return clone(node); //这题参数一样为什么还是分开呢?从实际意义出发就好理解了。
    }
    private Node clone(Node node){
     	//1.如果图是空的,直接返回
        if(node==null) return null; 
        //4.万一拷到了已经放进map的点咋办?做了5,就可以直接取,而不用重复拷贝啦。
        if(map.containsKey(node.val)) return map.get(node.val);
        //2.如果不空,拷贝该点,并创建一个空的邻接表
        Node newNode = new Node(node.val,new ArrayList<>()); 
        //5.我得提前标记一下,放进map,需要时取就好了。
        map.put(newNode.val,newNode);
        //拷贝该点的每个邻居点
        for(Node neighbor:node.neighbors){
            newNode.neighbors.add(clone(neighbor));
        }
        //...100.最后的最后,最开始的点终于递归拷贝完成并返回。
        return newNode;
    }
}

6.火柴摆矩形

(先用的贪心,发现不行,还是用dfs)

//Remember the story of Little Match Girl? By now, you know exactly what matchst
//icks the little match girl has, please find out a way you can make one square by
// using up all those matchsticks. You should not break any stick, but you can lin
//k them up, and each matchstick must be used exactly one time. 
//
// Your input will be several matchsticks the girl has, represented with their s
//tick length. Your output will either be true or false, to represent whether you 
//could make one square using all the matchsticks the little match girl has. 
//
// Example 1: 
// 
//Input: [1,1,2,2,2]
//Output: true
//
//Explanation: You can form a square with length 2, one side of the square came 
//two sticks with length 1.
// 
// 
//
// Example 2: 
// 
//Input: [3,3,3,3,4]
//Output: false
//
//Explanation: You cannot find a way to form a square with all the matchsticks.
// 
// 
//
// Note: 
// 
// The length sum of the given matchsticks is in the range of 0 to 10^9.
// The length of the given matchstick array will not exceed 15. 


//leetcode submit region begin(Prohibit modification and deletion)

class Solution {
    public boolean makesquare(int[] nums) {
        if(nums.length<4) return false;
        int sum = 0;
        for (int i = 0; i < nums.length; i++)  sum += nums[i];
        if(sum%4!=0) return false;
        int edge = sum/4;
        for (int i = 0; i < nums.length; i++) {
            if(nums[i]>edge) return false;
        }
        //以上是一系列判断,长度不足4||不能被4整除||有任何一个num大于edge均需要返回false
        //下面是dfs,核心思想是,我拿着第一根火柴开始往四个容器里试,走不通就会退,重试。
        return dfs(nums,edge,new int[4],0);
    }
    private boolean dfs(int[] nums,int target, int[] count, int idx){
        if(idx==nums.length){
            if(count[0]==target && count[1]==target && count[2]==target) return true;
            else return false;
        }

        for (int i = 0; i < count.length; i++) {
            if(nums[idx]+count[i]>target) continue;
            count[i]+=nums[idx];
            if(dfs(nums,target,count,idx+1)) return true;
            count[i]-=nums[idx];
        }
        
        return false;
    }
}

7. 列举所有上升子序列

到这里开始有点感觉,自己写的,性能不是最优,可以查看leetcode评论

//Given an integer array, your task is to find all the different possible increa
//sing subsequences of the given array, and the length of an increasing subsequenc
//e should be at least 2. 
//
// 
//
// Example: 
//
// 
//Input: [4, 6, 7, 7]
//Output: [[4, 6], [4, 7], [4, 6, 7], [4, 6, 7, 7], [6, 7], [6, 7, 7], [7,7], [4
//,7,7]]
// 
//
// 
// Constraints: 
//
// 
// The length of the given array will not exceed 15. 
// The range of integer in the given array is [-100,100]. 
// The given array may contain duplicates, and two equal integers should also be
// considered as a special case of increasing sequence. 


//leetcode submit region begin(Prohibit modification and deletion)
class Solution {
    List<List<Integer>> res = new ArrayList<>();
    //用到set是为了避免重复,标记用
    Set<List<Integer>> set = new HashSet<>();
    public List<List<Integer>> findSubsequences(int[] nums) {
        if(nums==null || nums.length==0) return res;
        dfs(nums,0,new ArrayList<Integer>());
        return res;
    }

    private void dfs(int[] nums,int idx, List<Integer> temp){
    	//递归出口
        if(temp.size()>1){
            if(isAscend(temp)){
            	//长度大于1且升序且不重复则加入
                if(!set.contains(temp))
                {
                    res.add(new ArrayList<Integer>(temp));
                    set.add(new ArrayList<Integer>(temp));
                    //注意加完之后不用return,接着往后加,
                    //看看能不能找到更长并且符合条件的上升序列
                }
            }
            //如果不是上升,后面的也没必要试了
            else return;
        }
        //以每个num为起点都要用到
        for (int i = idx; i < nums.length; i++) {
            temp.add(nums[i]);
            dfs(nums,i+1,temp);
            temp.remove(temp.size()-1);
        }
    }
				46
				467
				4677
				47
				477  //4开头的
				67
				677  //6开头的
				77	 //7开头的
    
	//判断升序
    private boolean isAscend(List<Integer> arr){
        for (int i = 0; i < arr.size()-1; i++) {
            if(arr.get(i+1)<arr.get(i)) return false;
        }
        return true;
    }
}

8.Number of Closed Islands

//Given a 2D grid consists of 0s (land) and 1s (water). An island is a maximal 4
//-directionally connected group of 0s and a closed island is an island totally (a
//ll left, top, right, bottom) surrounded by 1s. 
//
// Return the number of closed islands. 
//
// 
// Example 1: 
//
// 
//
// 
//Input: grid = [[1,1,1,1,1,1,1,0],[1,0,0,0,0,1,1,0],[1,0,1,0,1,1,1,0],[1,0,0,0,
//0,1,0,1],[1,1,1,1,1,1,1,0]]
//Output: 2
//Explanation: 
//Islands in gray are closed because they are completely surrounded by water (gr
//oup of 1s). 
//
// Example 2: 
//
// 
//
// 
//Input: grid = [[0,0,1,0,0],[0,1,0,1,0],[0,1,1,1,0]]
//Output: 1
// 
//
// Example 3: 
//
// 
//Input: grid = [[1,1,1,1,1,1,1],
//               [1,0,0,0,0,0,1],
//               [1,0,1,1,1,0,1],
//               [1,0,1,0,1,0,1],
//               [1,0,1,1,1,0,1],
//               [1,0,0,0,0,0,1],
//               [1,1,1,1,1,1,1]]
//Output: 2
// 
//
// 
// Constraints: 
//
// 
// 1 <= grid.length, grid[0].length <= 100 
// 0 <= grid[i][j] <=1 
// 
class Solution {
    int[][] dirs = new int[][]{{-1,0},{1,0},{0,-1},{0,1}};
    int res = 0;
    public int closedIsland(int[][] grid) {
        int m = grid.length, n= grid[0].length;
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if(i*j*(i-m+1)*(j-n+1)==0) dfs(grid, i, j);
            }
        }
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if(grid[i][j]==0){
                    res++;
                    dfs(grid,i,j);
                }
            }
        }
        return res;
    }

    public void dfs(int[][] g, int x, int y){
        if(x<0 || x>g.length-1 || y<0 || y>g[0].length-1 || g[x][y]==1) return;
        g[x][y] = 1;
        for(int[] dir:dirs){
            dfs(g,x+dir[0], y+dir[1]);
        }
    }
}

9. Number of Operations to Make Network Connected

//There are n computers numbered from 0 to n-1 connected by ethernet cables conn
//ections forming a network where connections[i] = [a, b] represents a connection 
//between computers a and b. Any computer can reach any other computer directly or
// indirectly through the network. 
//
// Given an initial computer network connections. You can extract certain cables
// between two directly connected computers, and place them between any pair of di
//sconnected computers to make them directly connected. Return the minimum number 
//of times you need to do this in order to make all the computers connected. If it
//'s not possible, return -1. 
//
// 
// Example 1: 
//
// 
//
// 
//Input: n = 4, connections = [[0,1],[0,2],[1,2]]
//Output: 1
//Explanation: Remove cable between computer 1 and 2 and place between computers
// 1 and 3.
// 
//
// Example 2: 
//
// 
//
// 
//Input: n = 6, connections = [[0,1],[0,2],[0,3],[1,2],[1,3]]
//Output: 2
// 
//
// Example 3: 
//
// 
//Input: n = 6, connections = [[0,1],[0,2],[0,3],[1,2]]
//Output: -1
//Explanation: There are not enough cables.
// 
//
// Example 4: 
//
// 
//Input: n = 5, connections = [[0,1],[0,2],[3,4],[2,3]]
//Output: 0
// 
//
// 
// Constraints: 
//
// 
// 1 <= n <= 10^5 
// 1 <= connections.length <= min(n*(n-1)/2, 10^5) 
// connections[i].length == 2 
// 0 <= connections[i][0], connections[i][1] < n 
// connections[i][0] != connections[i][1] 
// There are no repeated connections. 
// No two computers are connected by more than one cable. 

class Solution {
    public int makeConnected(int n, int[][] connections) {
        if(connections.length<n-1) return -1;
        HashMap<Integer, ArrayList<Integer>> graph = new HashMap<>();
        for (int i = 0; i < n; i++) {
            graph.put(i,new ArrayList<Integer>());
        }
        for (int i = 0; i < connections.length; i++) {
            graph.get(connections[i][0]).add(connections[i][1]);
            graph.get(connections[i][1]).add(connections[i][0]);
        }
        int blocks = 0;
        boolean[] vis = new boolean[n];
        for (int i = 0; i < n; i++) {
            blocks+=dfs(i,graph,vis);
        }
        return blocks-1;
    }
    int dfs(int v, HashMap<Integer, ArrayList<Integer>> map, boolean[] vis){
        if(vis[v]) return 0;
        vis[v] = true;
        for (int i = 0; i < map.get(v).size(); i++) {
            System.out.println(map.get(v).get(i)+" ");
        }
        for(Integer next:map.get(v)){
            dfs(next,map,vis);
        }
        return 1;
    }
}

精华

最后的最后,给出笔者总结出的做dfs的思想(注意是思想,不是模板!),请参考如下:


 - 常常用到一个数组作为标记visited[]
 - 传参!传参!传什么参!很重要!
 - 结合大量实战练习才能体会精妙!!!!
 - 形式如下:
 
 dfs(某状态) //怎么确定参数(很灵活)?<----出口决定   --->可以做哪些选择
 	如果搜出一种结果,即返回;
 	在所有能做的选择中: //<------visited[]决定
 		做出选择并标记做过; //<---用visited[]
 		dfs(选择后的状态);
 		撤销该选择以及该记录; //<----假装自己没做过【看不见我看不见我看不见我】

关于所有能做的选择的一点点说明:
他既可以是这样式儿的:
(循环形式表示)在这里插入图片描述
也可以是这样式儿的:
分行列举(实质是一样的)
在这里插入图片描述
包括上面的例子你也可以回过头去对应这个思路看一看,加深理解。

以上就是能通往运用dfs自如的入口,只有通过大量练习加以辅助,才能够真正融会贯通,加油~

后记

重点放在第一句, " 就 上 面 这 七 题 肯 定 是 不 够 的 ! 就 上 面 这 七 题 肯 定 是 不 够 的 " {\color{red}"就上面这七题肯定是不够的!就上面这七题肯定是不够的"} "!"。希望这上面几道题目可以让你对dfs的一般难度题有一定的了解,可以为你后面大量刷题做个铺垫,目录还是前言那些,感觉一般难度的题目差不多了,可以去挑战一下hard级别的,在有兴趣的可以专门去研究一下相关的算法,结合着图的部分一起看(毕竟关于图的题目就是笔试难度上限了)。

奥里给!

创作不易,你的鼓励是我创作的动力,如果你有收获,点个赞吧👍
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TechGuide

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值