题目
给定一个可包含重复数字的序列 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
}
}