1. 程式人生 > 實用技巧 >dfs-入門模板

dfs-入門模板

模板

void dfs()//引數用來表示狀態  
{  
    if(到達終點狀態)  
    {  
        ...//根據題意新增  
        return;  
    }  
    if(越界或者是不合法狀態)  
        return;  
    if(特殊狀態)//剪枝
        return ;
    for(擴充套件方式)  
    {  
        if(擴充套件方式所達到狀態合法)  
        {  
            修改操作;//根據題意來新增  
            標記;  
            dfs();  
            (還原標記);  
            
//是否還原標記根據題意 //如果加上(還原標記)就是 回溯法 } } }

46. 全排列

class Solution {
public:
    vector<vector<int>> res;
    vector<int> vis;
    vector<vector<int>> permute(vector<int>& nums) {
        vector<int> path;
        vis.resize(nums.size(), 
0); dfs(nums, path, 0); return res; } void dfs(vector<int> & nums, vector<int>& path, int len){//引數表示狀態 if(len == nums.size()){//遞迴出口 res.push_back(path);return; } for(int i = 0;i < nums.size(); i++){//擴充套件方式 if(vis[i] == 0
){//擴充套件方式合法 path.push_back(nums[i]); vis[i] = 1; dfs(nums,path,len + 1); vis[i] = 0; path.pop_back(); } } } };

47. 全排列 II排序去重

class Solution {
public:
    vector<vector<int>> res;
    vector<int> vis;
    vector<vector<int>> permuteUnique(vector<int>& nums) {
        sort(nums.begin(),nums.end());
        vis.resize(nums.size(),0);
        vector<int> path;
        dfs(nums,path, 0); 
        return res;
    }
    void dfs(vector<int>& nums, vector<int>& path, int depth){
        if(depth == nums.size()){//遞迴出口
            res.push_back(path);
            return;
        }
        for(int i = 0; i < nums.size(); i++){
            //在同一深度只會遍歷第一個相同的數字,不同深度時vis[i-1] = 1
            if(i && nums[i] == nums[i-1] && vis[i-1] == 0) continue;
            if(vis[i] == 0){
                vis[i] = 1;
                path.push_back(nums[i]);
                dfs(nums,path,depth + 1);
                vis[i] = 0;
                path.pop_back();
            }
        }
    }
};

491. 遞增子序列

class Solution {
public:
    vector<vector<int>> res;
    vector<int> vis;
    vector<vector<int>> findSubsequences(vector<int>& nums) {
            vis.resize(nums.size(),0);
           vector<int> path;
           dfs(nums,path,0);
           return res;
    }
    void dfs(vector<int> & nums, vector<int>& path, int start){//引數表示狀態,從前往後,depth改為start
        if(path.size() >= 2){//過程狀態也要記錄
                res.push_back(path);
        }   
        if(start == nums.size()) return; 
        unordered_set<int> mp;//去重   
        for(int i = start;i < nums.size(); i++){//擴充套件方式
            //if(vis[i] == 0){這裡不需要vis
            if((path.size() == 0 || nums[i] >= path.back()) && mp.count(nums[i]) == 0){
                mp.insert(nums[i]);
                path.push_back(nums[i]);
                dfs(nums,path,i + 1);//這裡別寫錯了
                path.pop_back();
            }
        } 
    }
};

39. 組合總和

元素可以重複利用且沒有順序,所以不要vis陣列

class Solution {
public:
    vector<vector<int>> res;
    vector<vector<int>> combinationSum(vector<int>& nums, int target) {
        vector<int> path;
        dfs(nums,path,0,target);
        return res;
    }
    void dfs(vector<int> &nums,vector<int>& path, int start, int target){
            //出口  
        if(target < 0) return;
        if(target == 0){
            res.push_back(path);
            return;
        }
        //遍歷
        for(int i = start; i <nums.size(); i++){
            path.push_back(nums[i]);
            dfs(nums,path,i, target - nums[i]);
            path.pop_back();
        }
    }
};

40. 組合總和 II比上題多了一個去重操作;

class Solution {
public:
    vector<vector<int>> res;
    vector<vector<int>> combinationSum2(vector<int>& nums, int target) {
        sort(nums.begin(),nums.end());//加個去重操作
        vector<int> path;
        dfs(nums,path,0,target);
        return res;
    }
    void dfs(vector<int> &nums,vector<int>& path, int start, int target){
            //出口  
        if(target < 0) return;
        if(target == 0){
            res.push_back(path);
            return;
        }
        //遍歷
        for(int i = start; i <nums.size(); i++){
            if(i > start && nums[i] == nums[i-1] ) continue;//注意是i > start
            path.push_back(nums[i]);
            dfs(nums,path,i+1, target - nums[i]); // start = i + 1
            path.pop_back();
        }
    }
};

78. 子集

class Solution {
public:
    vector<vector<int>> res;
    vector<int> vis;
    vector<vector<int>> subsets(vector<int>& nums) {
            vis.resize(nums.size(),0);
           vector<int> path;
           dfs(nums,path,0);
           return res;
    }
    void dfs(vector<int> & nums, vector<int>& path, int start){//引數表示狀態,從前往後,depth改為start
         res.push_back(path);   
        if(start == nums.size()) return;    
        for(int i = start;i < nums.size(); i++){//擴充套件方式
                //似乎沒條件
                path.push_back(nums[i]);
                dfs(nums,path,i + 1);//這裡別寫錯了
                path.pop_back();
        } 
    }
};

90. 子集 II上題基礎上加個去重

class Solution {
public:
    vector<vector<int>> res;
    vector<int> vis;
    vector<vector<int>> subsetsWithDup(vector<int>& nums) {
            sort(nums.begin(), nums.end());//排序便於去重
            vis.resize(nums.size(),0);
           vector<int> path;
           dfs(nums,path,0);
           return res;
    }
    void dfs(vector<int> & nums, vector<int>& path, int start){//引數表示狀態,從前往後,depth改為start
         res.push_back(path);   
        if(start == nums.size()) return;    
        for(int i = start;i < nums.size(); i++){//擴充套件方式
                if(i > start && nums[i] == nums[i-1]) continue; //去重
                path.push_back(nums[i]);
                dfs(nums,path,i + 1);//這裡別寫錯了
                path.pop_back();
        } 
    }
};

進階:N皇后問題

51. N皇后

class Solution {
public:
    vector<vector<string>> res;
    vector<vector<string>> solveNQueens(int n) {     
        string t = "";
        for(int i = 0; i < n; i++) t += '.';
        vector<string> path(n,t);
        vector<vector<int>> vis(n, vector<int>(n,0));
        dfs(path,vis,n,0);
        return res;
    }
    void dfs(vector<string>& path,vector<vector<int>> &vis, int& n, int row){
        if(row == n){//遞迴出口,前n行全部被賦值
            res.push_back(path);return;
        }
        for(int j = 0; j < n; j++){//遍歷一行
            if(vis[row][j] == 0){//條件
                path[row][j] = 'Q';
                //注意,不能直接讓vis變1和變0,否則後來的修改可能會改變原來的修改
                for(int i = row; i < n; i++)vis[i][j]++;//該列
                for(int i = row; i < n; i++){//對角線
                    if(j + i - row < n) vis[i][j + i - row]++;
                    if(j + row - i >= 0) vis[i][j + row - i]++;
                } 
                dfs(path, vis, n, row + 1);
                path[row][j] = '.';
                for(int i = row; i < n; i++)vis[i][j]--;//該列
                for(int i = row; i < n; i++){//對角線
                    if(j + i - row < n) vis[i][j + i - row]--;
                    if(j + row - i >= 0) vis[i][j + row - i]--;
                } 
            }
        }
    }
};

37. 解數獨

class Solution {
public:
    int col[9][9] = {0};
    int row[9][9] = {0};
    int box[9][9] = {0};
    void solveSudoku(vector<vector<char>>& board) {
        int n = board.size();
        //初始化
        for(int i = 0; i <9; i++)
            for(int j = 0; j < 9; j++){
                if(board[i][j] != '.'){
                    int t = board[i][j] - '1';
                    col[j][t]++;
                    row[i][t]++;
                    box[i/3*3+ j/3][t]++;
                }
            }
        dfs(board, 0, 0);
    }
    //傳參 int a[][9] 或者 int (*a)[9] 而不是 (int*)[9] a
    // box x/3*3 + y/3 而不是 x/3 + y/3;
    // (y + 1)%3 而不是 (++y)/3
    bool dfs(vector<vector<char>>& board,  int x, int y){
        if(x == 9) return true;//遞迴出口
        //特殊狀態
        if(board[x][y] != '.') return dfs(board,x + (y==8),(++y)%9);
        for(int k = 0; k < 9; k++){//遍歷
            //條件
            if(row[x][k] || col[y][k] || box[x/3*3 + y/3][k]) continue;
            board[x][y]  = k + '1';
            row[x][k]++;col[y][k]++;box[x/3*3 + y/3][k]++;
            if(dfs(board,x + (y==8),(y + 1)%9)) return true;//找到一個解就退出
            board[x][y]  = '.';
            row[x][k]--;col[y][k]--;box[x/3*3 + y/3][k]--;
        }
        return false;
    }
};