這篇文章會對dfs進行乙個總結,列舉的題目則是從leetcode上面選的;
有三個方面,分別是輸入資料、狀態轉換圖、求解目標;
輸入資料:如果是遞迴資料結構,如單鏈表,二叉樹,集合,則百分之百可以使用深搜;如果是非遞迴資料結構,比如一維陣列、二維陣列、字串、圖,則概率要小一些;
狀態轉換圖:樹或者圖;
輸入資料:必須要走到最深(比如對於樹,必須要走到葉子結點)才能得到乙個解,這種情況比較適合用深搜;
/**
* dfs模版
* @param input 輸入資料指標
* @param path 當前路徑,也是中間結果
* @param result 存放最終結果
* @param gap 標記當前位置或距離目標的距離
** @return 路徑長度,如果是路徑本身,則不需要返回長度
*/template void dfs(type & input, type & path, type & result, int cur or gap)
if (可以剪枝) return ;
for (...)
}
大概遇見這幾種題型:
例題為求二叉樹路徑
貼上**:
/**
* 遞迴將更新字串,到達葉結點時加入到陣列中
** @param result <#result description#>
* @param root <#root description#>
* @param t <#t description#>
*/void binarytreepaths(vector& result, treenode* root, string t)
if (root->left) binarytreepaths(result, root->left, t + "->" + to_string(root->left->val));
if (root->right) binarytreepaths(result, root->right, t + "->" + to_string(root->right->val));
}vectorbinarytreepaths(treenode* root)
因為這裡面涉及的內容很多,所以就以拓撲排序為例,例題為選課順序;
貼上**:
/**
* 判斷有向圖是否有環
* 通過dfs找環
** @param matrix <#matrix description#>
* @param visited <#visited description#>
* @param idx <#idx description#>
* @param flag <#flag description#>
** @return <#return value description#>
*/bool dfs(vector> &matrix, unordered_set&visited, int idx, vector&flag)
}visited.erase(idx);
return false;
}bool canfinish(int numcourses, vector>& prerequisites)
unordered_setvisited; // 記錄乙個遞迴訪問過的結點
vectorflag(numcourses, false); // 記錄是否訪問過結點
/*** 遍歷所有課程,也就是結點
* 判斷是否標記過結點,如果沒有則進行dfs判斷是否存在迴路,存在迴路則返回false
*/for (int i = 0; i < numcourses; ++i)
return true;
}
這裡分為鍊錶構造和陣列構造,或是已知前中後序列,構造二叉樹
這裡以前序和後序構造二叉樹為例,貼上**:
/**
* 利用遞迴進行計算左子樹和右子樹
** @param inorder <#inorder description#>
* @param postorder <#postorder description#>
* @param instart <#instart description#>
* @param inend <#inend description#>
* @param poststart <#poststart description#>
* @param postend <#postend description#>
** @return <#return value description#>
*/treenode* createtree(vector& inorder, vector& postorder, int instart, int inend, int poststart, int postend)
}// 分別定為左子樹和右子樹 (需要注意子樹的邊界問題!!!!!)
root->left = createtree(inorder, postorder, instart, index - 1, poststart, poststart - instart + index - 1);
root->right = createtree(inorder, postorder, index + 1, inend, postend - inend + index, postend - 1);
return root;
}treenode* buildtree(vector& inorder, vector& postorder)
以longest increasing path in a matrix為例
貼上**:
/**
* 方法和上面類似,不過利用dirs+迴圈可以使函式簡化
*/vector> dirs = , , , };
int helper(vector>& matrix, vector>& visit, int i, int j, int m, int n)
visit[i][j] = result;
return result;
}int longestincreasingpath2(vector>& matrix)
}return result;
}
以populating next right pointers in each node為例,貼上**:
/**
* 遞迴實現
** @param root <#root description#>
*/void createtree(treelinknode *root)
void connect2(treelinknode *root)
以remove invalid parentheses為例,貼上**:
/**
* dfs+剪枝
** @param pair 遇見括號的個數
* @param index 記錄字串s的當前位置
* @param remove_left 左括號需要刪除的個數
* @param remove_right 右括號需要刪除的個數
* @param s 原始字串
* @param solution 生成字串
* @param result 儲存所有的字串結果
*/void helper(int pair, int index, int remove_left, int remove_right, const string& s, string solution, unordered_set&result)
if (s[index] == '(')
else if (s[index] == ')')
else
}vectorremoveinvalidparentheses(string s)
helper(0, 0, remove_left, remove_right, s, "", result);
return vector(result.begin(), result.end());
}
回溯法 = 深搜+剪枝遞迴有兩種加速策略,一種是剪枝,對中間結果進行判斷,提前返回;一種是快取,快取中間結果,防止重複計算,用空間換時間;遞迴一定是深搜,深搜不一定是遞迴,因為還可以迭代實現;
遞迴加快取,就是memorization,即自頂向下+快取,memorization不一定用遞迴,就像深搜不一定用遞迴,可以在迭代中使用memorization,遞迴也不一定memorization,可以用memorization加速,但不是必須的;
演算法 dfs總結
用壓棧的方法來進行迭代 最關鍵的是用null標誌來區分每個遞迴呼叫棧,不同遍歷順序只用改變壓棧順序即可 先序遍歷 右節點 左結點 根節點 中序遍歷 右節點 根節點 左結點 後序遍歷 根節點 右節點 左結點 我們在每次處理過的結點壓棧後,在給他後面壓乙個空結點,這樣棧頂元素如果是null就說明他下面的...
BFS與DFS常見演算法總結
關於bfs於dfs一般用於在圖論中來遍歷圖 樹是乙個特殊的圖 最難的就在於我們常常不知道這是乙個可以用bfs dfs來解決的乙個問題,因為通常題目都表達得很隱晦,需要我們取轉化取構建乙個圖,難度較大。同時可能也需要結合stack與queue這兩種資料結構來解決問題,或者能用bfs dfs解決的問題有...
演算法總結 DFS 深度優先搜尋
目錄二 dfs的具體實現 三 剪枝 四 練習 1.什麼是dfs 深度優先搜尋演算法,又稱dfs depth first search dfs演算法是一種搜尋演算法,而搜尋演算法實質上是一種列舉,即借助計算機的高效能來有目的地列舉乙個問題的部分情況或這個問題的所有情況,進而求出問題的解的一種方法。2....