回溯基礎css
先看一個使用回溯方法求集合子集的例子(78. Subsets),如下代碼基本說明了回溯使用的基本框架:html
//78. Subsets class Solution { private: void backtrack(vector<vector<int>>& res,vector<int>& tmp,vector<int>& nums,int start){ res.push_back(tmp); //知足必定條件下將當前數據加入結果集 for(int i=start;i<nums.size();i++){ tmp.push_back(nums[i]); //選擇一條路徑 backtrack(res,tmp,nums,i+1); //DFS朝當前路徑行進 tmp.pop_back(); //回退路徑 } } public: vector<vector<int>> subsets(vector<int>& nums) { vector<vector<int>> res; vector<int> tmp; backtrack(res,tmp,nums,0); return res; } };
即回溯方法主要有如下四個步驟:python
1. 知足必定條件下將當前數據加入結果集 (或檢查到不知足要求立即返回) 2. 選擇一條路徑 3. DFS向前進行 4. 回退路徑
一些狀況下須要對數據進行預先處理,或在第2步直接檢查以決定是否拋棄當前路徑,以免過多地遞歸、帶來時間損耗。換而言之,不知足條件的路徑越早拋棄越好。git
理解回溯github
回溯方法用到遞歸,涉及到遞歸讓咱們理解起來就不那麼直觀。下圖直觀展現了以上Subsets求解代碼的執行過程,第5步開始出現路徑回退:app
能夠把回溯的執行理解爲一顆樹從根到葉、從左到右的展開過程。圖片來源 這裏框架
回溯時間複雜度spa
一樣由於用到遞歸,時間複雜度亦不可以直觀地計算,以上Subsets問題比較容易地能看出來爲O(2^n)。若是對遞歸過程計算時間複雜度,詳見 這裏3d
相關LeetCode題:code