leetcode#47 全排列II

本文详细解析LeetCode第47题全排列II,通过使用标记数组vis和排序,优化回溯算法避免重复排列。核心思路在于处理重复数字时,将相同数字视为一个整体进行选择,避免无效的递归。代码实现中,当遇到重复数字且前一个位置未被选择时,跳过本次循环,有效减少计算量。
摘要由CSDN通过智能技术生成

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;
    }
};
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值