栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

LeetCode 47. 全排列 II

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

LeetCode 47. 全排列 II

题目描述

47. 全排列 II

解法

这道题同样还是回溯剪枝的问题,但是这里的剪枝有点技巧。我们先来分析一下,例如, n u m s = [ 1 , 2 , 2 ′ ] nums = [1,2,2'] nums=[1,2,2′],不剪枝的话,会得到如下的结果

[
    [1,2,2'],[1,2',2],
    [2,1,2'],[2,2',1],
    [2',1,2],[2',2,1]
]

如果我们保证相同元素在排列中的相对位置保持不变,比如说 n u m s = [ 1 , 2 , 2 ′ ] nums = [1,2,2'] nums=[1,2,2′] 这个例子,我保持排列中 2 2 2 一直在 2 ′ 2' 2′ 前面。这样的话,你从上面 6 个排列中只能挑出 3 个排列符合这个条件:

[ 
	[1,2,2'],[2,1,2'],[2,2',1] 
]

仔细思考,应该很容易明白其中的原理:

标准全排列算法之所以出现重复,是因为把相同元素形成的排列序列视为不同的序列,但实际上它们应该是相同的;而如果固定相同元素形成的序列顺序,当然就避免了重复

那么反映到代码上,你注意看这个剪枝逻辑:

// 新添加的剪枝逻辑,固定相同的元素在排列中的相对位置
if (i > 0 && nums[i] == nums[i - 1] && !used[i - 1]) {
    // 如果前面的相邻相等元素没有用过,则跳过
    continue;
}
// 选择 nums[i]

完整实现如下

class Solution {
public:

    vector> res;

    vector> permuteUnique(vector& nums) {
        vector track;
        vector used(nums.size(), 0);
        sort(nums.begin(), nums.end());
        backtrace(nums, track, used);
        return res;
    }

    void backtrace(vector& nums, vector& track, vector& used)
    {
        if (track.size() == nums.size())
        {
            res.push_back(track);
            return;
        }

        for (int i = 0; i < nums.size(); i++)
        {
            if (used[i]) continue;
            if (i > 0 && nums[i] == nums[i - 1] && used[i - 1] == 0) continue;

            track.push_back(nums[i]);
            used[i] = 1;
            backtrace(nums, track, used);
            used[i] = 0;
            track.pop_back();
        }
    }
};
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/955098.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号