DFS

LC46. Permutations

给一个包含不重复元素的数组,返回所有不同的排列

分析:用dfs枚举,用一个数组 vis 记录某个元素是否已经被使用,使用的时候 vis[i] = 1 ,回溯的时候 vis[i] = 0 ,用 idx 记录当前排列要放数据的位置

class Solution {
public:
    vector<int> nu, vis, cur;
    vector<vector<int>> res;
    int n;
    void dfs(int idx) {
        if (idx == n) {
            res.push_back(cur);
            return;
        }
        for (int i = 0; i < n; ++i) {
            if (vis[i]) continue;
            vis[i] = 1;
            cur[idx] = nu[i];
            dfs(idx + 1);
            vis[i] = 0;
        }
    }
    vector<vector<int>> permute(vector<int>& nums) {
        n = nums.size();
        if (!n) return res;
        nu = nums;
        vis.assign(n, 0);
        cur.assign(n, 0);
        dfs(0);
        return res;
    }
};

 还有一种方法,还是dfs枚举,每次按序交换两个元素的位置

class Solution {
public:
    vector<vector<int>> res;
    int n;
    void dfs(vector<int>& nums, int begin) {
        if (begin == n) {
            res.push_back(nums);
            return;
        }
        for (int i = begin; i < n; ++i) {
            swap(nums[begin], nums[i]);
            dfs(nums, begin + 1);
            swap(nums[begin], nums[i]);
        }
    }
    vector<vector<int>> permute(vector<int>& nums) {
        n = nums.size();
        dfs(nums, 0);
        return res;
    }
};

 LC47. Permutations II

给一个包含重复元素的数组,返回所有不同的排列

方法一:dfs枚举的时候,如果当前数字和前一个数字相等,且前一个数字没有被使用,那么当前数字也不会用

class Solution {
public:
    vector<int> cur, nu, vis;
    vector<vector<int>> res;
    int n;
    void dfs(int idx) {
        if (idx == n) {
            res.push_back(cur);
            return;
        }
        for (int i = 0; i < n; ++i) {
            if (vis[i]) continue;
            if (i > 0 && nu[i] == nu[i - 1] && !vis[i - 1]) continue;
            vis[i] = 1;
            cur[idx] = nu[i];
            dfs(idx + 1);
            vis[i] = 0;
        }
    }
    vector<vector<int>> permuteUnique(vector<int>& nums) {
        n = nums.size();
        if (!n) return res;
        nu = nums;
        sort(nu.begin(), nu.end());
        cur.assign(n, 0);
        vis.assign(n, 0);
        dfs(0);
        return res;
    }
};

 方法二:用一个 cnt 数组记录每个数字出现的次数,因为数据没有给范围,所以 cnt[i] 记录每个 nu[i] 出现的次数,即记录下标,原数组需要去重并统计出现次数

class Solution {
public:
    vector<int> nu, cnt, cur;
    vector<vector<int>> res;
    int m, n;
    void dfs(int idx) {
        if (idx == n) {
            res.push_back(cur);
            return;
        }
        for (int i = 0; i < m; ++i) {
            if (cnt[i] == 0) continue;
            cnt[i]--;
            cur[idx] = nu[i];
            dfs(idx + 1);
            cnt[i]++;
        }
    }
    vector<vector<int>> permuteUnique(vector<int>& nums) {
        n = nums.size();
        if (!n) return res;
        sort(nums.begin(), nums.end());
        int i = 0, j = 0;
        m = 0;
        while (i < n) {
            nu.push_back(nums[i]);
            cnt.push_back(1);
            j = i + 1;
            while (j < n && nums[j] == nums[i]) {
                cnt[m]++;
                j++;
            }
            i = j;
            m++;
        }
        cur.assign(n, 0);
        dfs(0);
        return res;
    }
};

 方法三:dfs + 交换元素,这种方法较难理解,不具有普遍性,dfs的数组参数是传值而不是传引用

class Solution {
public:
    vector<vector<int>> permuteUnique(vector<int>& nums) {
        vector<vector<int>> result;
        sort(nums.begin(), nums.end());
        help(nums, 0, result);
        return result;
    }
    
    void help(vector<int> nums, int begin, vector<vector<int>>& result) {
        if (begin == nums.size() - 1) {
            result.push_back(nums);
            return;
        }
        for (int i = begin; i < nums.size(); ++i) {
            if (i != begin && nums[i] == nums[begin]) continue;
            else {
                swap(nums[i], nums[begin]);
                help(nums, begin + 1, result);
            }
        }
    }
};
原文地址:https://www.cnblogs.com/betaa/p/12446910.html