力扣小白刷题之47题全排列Ⅱ

题目描述

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

思路

序列中的元素可重复,但返回的结果不能重复。
在一定会产生重复结果的地方剪枝。
一个比较容易想到的办法是在结果集中去重,但是这些结果集中的元素是一个又一个的列表,对列表去重不像用哈希表对基本元素去重那样容易。
如果要比较两个列表是否一样,一个很显然的方法是分别排序,然后逐个对比。既然要排序,我们可以在搜索之前就对候选数组排序,一旦发现这一支搜索下去可能搜索到重复的元素就停止搜索,这样结果集中不会包含重复元素。
在这里插入图片描述
产生重复结点的地方,这是图中标注了“剪刀”,且被绿色框框住的地方。
在图中 ② 处,搜索的数也和上次一样,但是上次的 1 还在使用中;
在图中 ① 处,搜索的数也和上一次一样,但是上一次的 1 刚刚被撤销,正是因为刚被撤销,下面的搜索中还会使用到,因此会产生重复,剪掉的就应该是这样的分支。
遇到两个相同数字,可以:

  1. 两个都选
  2. 两个都不选
  3. 如果只选一个,那么选哪一个都可以,只有这种情况需要剪枝。

这部分的剪枝条件为:和前一个元素值相同(此时隐含这个元素的index>0),并且前一个元素还没有被使用过。

还有一个剪枝条件:用过的元素不能再使用。

代码

在这里插入图片描述

一个问题

两种不同剪枝条件(!visited[i - 1] ) 和 (visited[i - 1] )的区别:

  1. !visited[i - 1]
    在这里插入图片描述

  2. visited[i - 1]在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  3. 结论
    visited[i - 1]前面加不加感叹号的区别仅在于保留的是相同元素的顺序索引还是倒序索引。很明显,顺序索引(即使用(!visited[i - 1])作为剪枝判定条件得到)的递归树剪枝更彻底,思路也相对更自然。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值