leetcode 47全排列II

该博客讨论了如何在包含重复数字的序列中生成不重复的全排列。通过排序和深度优先搜索(DFS)算法,实现了在遍历过程中利用树层或树枝去重的方法。代码示例展示了两种实现方式,分别使用树层和树枝去重条件进行跳过,确保不会产生重复的排列组合。
摘要由CSDN通过智能技术生成
题目

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

示例

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

解析

和上一题不同的是,包含了重复的数字,要不重复的,根据之前的经验,要先排序,将大小相同的放在一起
然后终止条件和上一道题相同;同时由于是全排列,不需要startIndex了,都是从0开始循环;
循环中的判断continue条件是: i > 0 && nums[i] == nums[i-1] && usedMap[i-1] == false,用来代表是在同一树层没有重复的元素(这道题写成usedMap[i-1] == true应该也能够,表示同一树枝无重复。即:本题用树枝去重或树层去重都可以)注意这道题的map中存的Key是下标,上一道的map的key是数组的元素的值。
先来好记的代码:

func permuteUnique (nums []int) [][]int {
   var res [][]int
   var path []int
   n := len(nums)
   if n <= 0 {
   	return res
   }
   sort.Ints(nums) // 去重一定要排序才有用
   usedMap := make(map[int]bool)
   var dfs func(int)
   dfs = func(i int) { // 还是要注意,下面的i只有在dfs是有用,其余的都需要用j来判断,不要写混了
   	if i == n {
   		tmp := make([]int, n)
   		copy(tmp, path)
   		res = append(res, tmp)
           return
   	}
   	for j := 0; j < n; j++ {
   		// 同一树层用过则跳过,这里要记住的是:树层去重用usedMap[j-1] == false。树枝去重用usedMap[j-1] == true
   		// 如果usedMap[j-1] == false,说明以nums[i-1]为某一层元素的选择已穷尽,以至于在回溯的时候将map数据置为false,于是后续会根据这个条件跳过同层相等元素
   		if j > 0 && nums[j] == nums[j-1] && usedMap[j-1] == false {
   			continue
   		}
   		if usedMap[j] {
   			continue
   		}
   		usedMap[j] = true
   		path = append(path, nums[j])
   		dfs(i + 1)
   		path = path[:len(path)-1]
   		usedMap[j] = false
   	}
   }
   dfs(0)
   return res
}

在这里单独强调一下代码中的这一行:if j > 0 && nums[j] == nums[j-1] && usedMap[j-1] == false
首先已经nums[j] == nums[j-1]了,正常来说map里面应该是true了,但这里还是false,那就意味这个时候已经是回溯成了false的阶段了,也就是同一树层的。
树枝的就比较好理解了,上面刚用过,现在还是true呢,故continue
之前的方法:

func permuteUnique(nums []int) [][]int {
   var path []int
   var res [][]int
   usedMap := make(map[int]bool)
   sort.Ints(nums)
   backtracking(nums, path, &res, usedMap)
   return res
}

func backtracking(nums []int, path []int, res *[][]int, usedMap map[int]bool) {
   //终止条件
   if len(path) == len(nums) {
   	temp := make([]int, len(path))
   	copy(temp, path)
   	*res = append(*res, temp)
   }
   for i := 0; i < len(nums); i++ {
   	// used[i - 1] == true,说明同一树枝nums[i - 1]使用过
   	// used[i - 1] == false,说明同一树层nums[i - 1]使用过
   	// 如果同一树层nums[i - 1]使用过则直接跳过
   	if i > 0 && nums[i] == nums[i-1] && usedMap[i-1] == false {
   		continue
   	}
   	if usedMap[i] {
   		continue
   	}
   	usedMap[i] = true
   	path = append(path, nums[i])
   	backtracking(nums, path, res, usedMap)
   	path = path[:len(path)-1]
   	usedMap[i] = false
   }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值