算法模板之DFS

一、基本模板

void dfs(vector<int> &nums, int pos, vector<int> &list, vector<vector<int>> &result, vector<int> &visited) {  //根据需要是否标记访问
    if(pos == nums.size()) {  //判断边界
        result.push_back(list);
        return;
    }    
    //for循环:尝试每一种可能(排列: 一定选)
    for (int i = 0; i <= n; i++) {  
        if(...) {  //根据需要是否去重
            list.push_back(nums[i]);

            dfs(nums, pos + 1, list, result);  //递归深搜
            
            list.pop_back();
        }
    }
    dfs(nums, pos + 1, list, result); //(子集:不选)
}

二、常见写法举例

        常见的DFS,按照解空间树的不同(子集树和排列树),大致上可以分为两类问题:子集和排列,它们的写法各不相同。

题型一:子集(Subsets)

1. LeetCode 78. 子集

给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。

说明:解集不能包含重复的子集。

示例:

输入: nums = [1,2,3]
输出:
[
  [3],
  [1],
  [2],
  [1,2,3],
  [1,3],
  [2,3],
  [1,2],
  []
]
    void dfs(vector<int> &nums, int pos, vector<int> &list, vector<vector<int>> &result) {
        if(pos == nums.size()) {  //判断边界
            result.push_back(list);
            return;
        }
        //正常情况下,这里会有一个for循环,来表示遍历所有可选的情况
        //由于这里只有选和不选两种情况,因此省略掉for循环,通过语句依次来表示两种情况的执行
        list.push_back(nums[pos]);  //选
        dfs(nums, pos + 1, list, result);
        list.pop_back();  //不选
        dfs(nums, pos + 1, list, result);
    }

    vector<vector<int>> subsets(vector<int>& nums) {
        vector<vector<int>> result;  //返回的结果
        vector<int> list;
        dfs(nums, 0, list, result);
        return result;
    }

2. LeetCode 90. 子集 II 

给定一个可能包含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。

说明:解集不能包含重复的子集。

示例:

输入: [1,2,2]
输出:
[
  [2],
  [1],
  [1,2,2],
  [2,2],
  [1,2],
  []
]
    void dfs(vector<int> &nums, int pos, vector<int> &list, vector<vector<int>> &result, vector<int> visited) {
        if(pos == nums.size()) {
            result.push_back(list);
            return;
        }
        if(pos == 0 || nums[pos - 1] != nums[pos] || visited[pos - 1]) {  //按条件选
            list.push_back(nums[pos]);
            visited[pos] = 1;
            dfs(nums, pos + 1, list, result, visited);
            //回退
            visited[pos] = 0;
            list.pop_back();
        }
        //不选
        dfs(nums, pos + 1, list, result, visited);
    }

    vector<vector<int>> subsetsWithDup(vector<int>& nums) {
        sort(nums.begin(), nums.end());  //先排序,保证相同的数字是连着的
        vector<vector<int>> result;
        vector<int> list;
        vector<int> visited(nums.size(), 0);  //是否访问过
        dfs(nums, 0, list, result, visited);
        return result;
    }

题型二:全排列(Permutations)

1. LeetCode 46. 全排列

给定一个没有重复数字的序列,返回其所有可能的全排列。

示例:

输入: [1,2,3]
输出:
[
  [1,2,3],
  [1,3,2],
  [2,1,3],
  [2,3,1],
  [3,1,2],
  [3,2,1]
]
    void dfs(vector<int> &nums, int pos, vector<int> &list, vector<vector<int>> &result, vector<int> &visited) {
        if(pos == nums.size()) {
            result.push_back(list);
            return;
        }
        for(int i = 0; i < nums.size(); i++) {
            if(!visited[i]) {  //当前的位置未访问
                list.push_back(nums[i]);
                visited[i] = 1;
                dfs(nums, pos + 1, list, result, visited);
                //回退
                visited[i] = 0;  
                list.pop_back(); 
            }
        }
    }

    vector<vector<int>> permute(vector<int>& nums) {
        vector<vector<int>> result;
        vector<int> list;
        vector<int> visited(nums.size(), 0);  //是否已经访问过(注意:先初始化为0)
        dfs(nums, 0, list, result, visited);
        return result;
    }

2. LeetCode 47. 全排列 II

给定一个可包含重复数字的序列,返回所有不重复的全排列。

示例:

输入: [1,1,2]
输出:
[
  [1,1,2],
  [1,2,1],
  [2,1,1]
]
    void dfs(vector<int> &nums, int pos, vector<int> &list, vector<vector<int>> &result, vector<int> &visited) {
        if(pos == nums.size()) {
            result.push_back(list);
            return;
        }
        for(int i = 0; i < nums.size(); i++) {
            //注意:去重的判断条件
            /*
            重复一定出现在两个相同的数字,数字按照访问位置误认为是不同的,因此出现了两次
                1. 第一个数字,肯定不重
                2. 后面的数字和前面的数字不同,肯定不重
                3. 后面的数字和前面的数字相同,并且前面的数字被访问过(目的是为了将两个数字看成一个整体,同增同减)
            */
            if(!visited[i] && (i == 0 || nums[i - 1] != nums[i] || visited[i - 1])) {
                list.push_back(nums[i]);
                visited[i] = 1;
                dfs(nums, pos + 1, list, result, visited);
                visited[i] = 0;
                list.pop_back();
            }
        }
    }

    vector<vector<int>> permuteUnique(vector<int>& nums) {
        sort(nums.begin(), nums.end());
        vector<vector<int>> result;
        vector<int> list;
        vector<int> visited(nums.size(), 0);
        dfs(nums, 0, list, result, visited);
        return result;
    }

猜你喜欢

转载自blog.csdn.net/qq_34519487/article/details/104456788