leetcode#47 全排列II

leetcode#47 全排列II

题目:

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

示例:
输入:nums = [1,1,2]
输出:
[[1,1,2],
 [1,2,1],
 [2,1,1]]

思路:

1、用标记数组vis,标记数组vis标记最好位置用没用过,因为你要标记数用没用过,不能用true or false,得用个数来描述还有多少个可用,其次如果数组里面的数很大,比如1e9,你就不能开vis[1e9]的数组了,需要离散化,比较麻烦,所以我们vis来标记位置。
2、考虑这个例子,你就明白了

2 1 1 2

第一种:
2 1 1 2
| | | |
2 1 1 2
第一个选2,第二个选第一个1,第三个选第二个1,第三个选第二个2.

第二种:
2 1 1 2
|  X  | 
2 1 1 1

第一个选2,第二个选第二个1,第三个选第一个1,第四个选第二个2.

我们发现两个一样的排列,区别是第二种中,我们没有选择第一个1,而选择了第二个1,效果是一样的,因为我们vis标记的是位置,导致两个1不同,但选出来的结果一样的。
对于当前要填写的位置,原先是,要么选第一个1,要么选第二个1不管选哪个选出来都是1,这样是不对的,我们,把所有1看成一个整体,我们改成要么选1,要么就不选了,也就是第一个1如果不选后面的1不选了。
因此加上一个下面的判断条件就可以了。

if (i > 0 && nums[i] == nums[i - 1] && !vis[i - 1])
    continue;

要让相等的数相邻才能判断,这也是我们排序的原因。

代码:

class Solution
{
public:
    int len;
    vector<bool> vis;
    vector<vector<int>> ans;
    vector<int> tmp;
    void dfs(int step, vector<int> &nums)
    {
        if (step == len)
        {
            ans.push_back(tmp);
            return;
        }
        for (int i = 0; i < len; ++i)
        {
            if (vis[i] || (i > 0 && nums[i] == nums[i - 1] && !vis[i - 1]))
                continue;
            vis[i] = true;
            tmp.push_back(nums[i]);
            dfs(step + 1, nums);
            tmp.pop_back();
            vis[i] = false;
        }
    }
    vector<vector<int>> permuteUnique(vector<int> &nums)
    {
        len = nums.size();
        sort(nums.begin(), nums.end());
        vis.resize(nums.size());
        dfs(0, nums);
        return ans;
    }
};

你可能感兴趣的:(leetcode,算法,leetcode,dfs,数据结构)