算法—leetcode—46

501 阅读2分钟

题目

(46). 全排列

题目描述

给定一个 没有重复 数字的序列,返回其所有可能的全排列。

示例

示例一

输入: [1,2,3]
输出:
[
  [1,2,3],
  [1,3,2],
  [2,1,3],
  [2,3,1],
  [3,1,2],
  [3,2,1]
]

思路

1、路径:也就是已经做出的选择;
2、选择列表:也就是你当前可以做的选择;
3、结束条件:也就是到达决策树底层,无法再做选择的条件。

路径:记录已经做过的选择;
选择列表:表示当前可以做的选择;
结束条件:就是遍历到树的底层,在这里就是选择列表为空的时候。

框架

for 选择 in 选择列表:
    # 做选择
    将该选择从选择列表移除
    路径.add(选择)
    backtrack(路径, 选择列表)
    # 撤销选择
    路径.remove(选择)
    将该选择再加入选择列表

代码

// permuteV2
// 全排列
// 回溯问题
// 产生问题
func permuteV2(nums []int) [][]int {
	result := [][]int{}

	// 是否存在
	visited := map[int]bool{}

	var backtrack func(path []int)
	backtrack = func(path []int) {
		// 满足结束条件
		if len(path) == len(nums) {
			// TODO 直接赋值 与 copy方式赋值结果不一致
			// 原因:切片赋值会直接拷贝原数组的地址,如果原数组发生了变化,赋值后的元素也会发生变化
			// 使用copy因为需要新创建一个切片,使用了新创建的地址,所以如此问题
			// temp := path

			// 通过copy方式赋值
			temp := make([]int, len(path))
			copy(temp, path)

			result = append(result, temp)
			log.Println("temp", temp, &path, result)
			return
		}

		for _, index := range nums {
			// 做选择
			if bo, ok := visited[index]; ok && bo {
				continue
			}
			visited[index] = true
			path = append(path, index)
			backtrack(path)
			log.Println(index, path)
			// 撤销选择
			visited[index] = false
			path = path[:len(path)-1]
			if len(path) == 0 {
				log.Println("一轮结束")
			}
		}

	}
	backtrack([]int{})
	return result
}

参考

来源:力扣(LeetCode)
链接:leetcode-cn.com/problems/pe…
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

labuladong的算法小抄