• 递归,回溯,DFS,BFS的理解和模板


    LeetCode 里面很大一部分题目都是属于这个范围,例如Path Sum用的就是递归+DFS,Path Sum2用的是递归+DFS+回溯

    这里参考了一些网上写得很不错的文章,总结一下理解与模板

    递归:就是出现这种情况的代码: (或者说是用到了栈)

    解答树角度:在dfs遍历一棵解答树      

    优点:结构简洁

    缺点:效率低,可能栈溢出

    递归的一般结构:

     1 void f()  
     2 {  
     3      if(符合边界条件)  
     4     {  
     5        ///////  
     6         return;  
     7     }  
     8       
     9      //某种形式的调用  
    10      f();  
    11 }  

    回溯:递归的一种,或者说是通过递归这种代码结构来实现回溯这个目的。回溯法可以被认为是一个有过剪枝的DFS过程。

    解答树角度:带回溯的dfs遍历一棵解答树

    回溯的一般结构:

     1 void dfs(int 当前状态)  
     2     {  
     3           if(当前状态为边界状态)  
     4           {  
     5             记录或输出  
     6             return;  
     7           }  
     8           for(i=0;i<n;i++)       //横向遍历解答树所有子节点  
     9          {  
    10                //扩展出一个子状态。  
    11                修改了全局变量  
    12                if(子状态满足约束条件)  
    13                 {  
    14                   dfs(子状态)  
    15                }  
    16                 恢复全局变量//回溯部分  
    17             }  
    18     }  

    BFS和DFS是相似。

    BFS(显式用队列)

    DFS(隐式用栈)(即递归)

    当然,对于DFS,用递归可能会造成栈溢出,所以也可以更改为显示栈。

    BFS:典型例题:P101 对于二叉树的层次遍历,P108对于图的走迷宫最短路径

     
    1 将(起始)首节点加入队列: q.push(head);  
    2                      标记首节点已经被访问:         isvisited[head]=true;  
    3                     以下自动反应:                       while(!q.empty())  
    4                                                                     {  
    5                                                                           int temp=q.front();  
    6                                                                            q.pop();  
    7                                                                           访问temp,并标记temp已被访问过,将temp的子相关节点加入队列  
    8                                                                           q.push(temp相关节点);  
    9                                                                     }  

    DFS:典型例题:P107黑白图像

    格式:将所有节点遍历一遍,在遍历每个节点是,DFS的遍历该节点相关的所有节点 

     
     1 void dfs(int x, int y)  
     2 {  
     3 if(!mat[x][y] || vis[x][y]) return;     // 曾经访问过这个格子,或者当前格子是白色  
     4 vis[x][y] = 1;                          // 标记(x,y)已访问过  
     5 dfs(x-1,y-1); dfs(x-1,y); dfs(x-1,y+1);  
     6 dfs(x-1,y);               dfs(x,y+1);  
     7 dfs(x+1,y-1); dfs(x+1,y); dfs(x+1,y+1); // 递归访问周围的八个格子  
     8 }  
     9 主循环:  
    10 for(int i = 1; i <= n; i++)  
    11 for(int j = 1; j <= n; j++)  
    12 if(!vis[i][j] && mat[i][j])  
    13 {  
    14 count++;  
    15 dfs(i,j);  
    16 } // 找到没有访问过的黑格  

    上述内容为转载内容。

  • 相关阅读:
    2017面试记录
    Bzoj1079:[SCOI2008]着色方案
    Bzoj1046: [HAOI2007]上升序列
    Luogu1121:环状最大两段子段和
    BZOJ 4698: [SDOI2008]Sandy的卡片
    [SPOJ]DISUBSTR:Distinct Substrings&[SPOJ]SUBST1:New Distinct Substrings
    HiHocoder1419 : 后缀数组四·重复旋律4&[SPOJ]REPEATS:Repeats
    Bzoj2946:[POI2000] 最长公共子串
    HiHocoder1415 : 后缀数组三·重复旋律3 & Poj2774:Long Long Message
    POJ3261:Milk Patterns
  • 原文地址:https://www.cnblogs.com/SarahLiu/p/5937532.html
Copyright © 2020-2023  润新知