前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >leetcode 47. 全排列 II---回溯篇6

leetcode 47. 全排列 II---回溯篇6

作者头像
大忽悠爱学习
发布2021-11-15 11:11:55
1720
发布2021-11-15 11:11:55
举报
文章被收录于专栏:c++与qt学习

全排列 | | 题解集合


引言

注意本题与leetcode 46. 全排列----回溯篇5的区别,区别在于本题所给的可选数组中出现了重复数字,并且要求我们返回所有不重复的全排列


回溯法

思路:

可选数组中出现重复数字,那么为什么重复数字会产生重复的全排列呢?

由图中可以看出,因为出现可选数组出现了两个相邻的数字1,因此,当我们选择第二个数字1时,下面的分支是于第一个数字1完全重复的,因此我们需要进行去重操作。

这里去重思路参考三数之和,先对可选数组进行排序,目的是让重复元素相邻,这里我们可以通过if (i > 0 && nums[i] == nums[i - 1]&&!visited[i-1]) continue;来判断是否有重复元素出现

这里i>0是因为当我们选择第一个数字的时候不需要考虑重复问题,并且当i=0时,nums[i-1]会溢出

这里还需要!visited[i-1]是因为重复问题的出现是因为有重复数字,即当我们将第一个重复数字1的所有排列都遍历一遍后,此时我们来对第二个重复数字1进行遍历会得到与前面一个完全一样的排列,因此这条分支要去掉,并且当我们来对第二个重复数字1进行遍历时,第一个重复数字1是处与没有被选择的状态

其实也就是在leetcode 46. 全排列----回溯篇5加上一个去重的操作,其余的操作于46题全排列完全一致

代码:

代码语言:javascript
复制
class Solution {
	vector<vector<int>> ret;
	vector<int> num;
	vector<bool> visited;
public:
	vector<vector<int>> permuteUnique(vector<int>& nums) 
	{
		if (nums.empty()) return ret;
		visited.resize(nums.size(), false);
		sort(nums.begin(), nums.end());
		backTrace(nums);
		return ret;
	}
	void backTrace(vector<int>& nums)
	{
		if (num.size() == nums.size())
		{
			ret.push_back(num);
			return;
		}
		for (int i =0; i < nums.size(); i++)
		{
			if (visited[i]) continue;
			// 剪枝条件:i > 0 是为了保证 nums[i - 1] 有意义
			//因为选择第一个数字的时候,不需要考虑重复的问题
		 // 写 !visited[i - 1] 是因为 nums[i - 1] 在深度优先遍历的过程中刚刚被撤销选择
			if (i > 0 && nums[i] == nums[i - 1]&&!visited[i-1]) continue;
			num.push_back(nums[i]);
			visited[i] = true;
			backTrace(nums);
			num.pop_back();
			visited[i] = false;
		}
	}
};

使用set容器去重

思路:

直接dfs全排列然后使用set暴力去重,即我们只需要将46题中用来存储全排列结果的vector替换成set即可

代码:

代码语言:javascript
复制
class Solution {
	set<vector<int>> ret;
	vector<int> num;
	vector<bool> visited;
public:
	vector<vector<int>> permuteUnique(vector<int>& nums) 
	{
		if (nums.empty()) return vector<vector<int>>();
		visited.resize(nums.size(), false);
		backTrace(nums);
		return vector<vector<int>>(ret.begin(),ret.end());
	}
	void backTrace(vector<int>& nums)
	{
		if (num.size() == nums.size())
		{
			ret.insert(num);
			return;
		}
		for (int i =0; i < nums.size(); i++)
		{
			if (visited[i]) continue;
			num.push_back(nums[i]);
			visited[i] = true;
			backTrace(nums);
			num.pop_back();
			visited[i] = false;
		}
	}
};

总结

对于由重复数字导致的重复结果去重法,有两种思路:

  1. 参考三数之和的去重思路,先对数组排序,然后使用相邻数字比较,将重复结果的分支去掉
  2. 使用set容器去重
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021/05/30 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 全排列 | | 题解集合
  • 引言
  • 回溯法
  • 使用set容器去重
  • 总结
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档