LeetCode每日一题 全排列 回溯算法

题目

给定一个 没有重复 数字的序列,返回其所有可能的全排列,如图:
在这里插入图片描述

分析

首先看到这道题,简单的暴力算法很难得出,因为数字的个数未知,一味地将数字不断的打乱重写,有两个问题,第一是很难做到将每种可能都列举出来,另一个是,时间复杂度过高,为阶层式的叠加,一旦给的数字过多,可能无法被计算得出。

看到这道题,按照我们正常的思路,应该会采取定一动一的方法来排列,这种思维方法和回溯算法的想法是一样的,比如我们先定好首个字母,以 [1,2,3] 为例,我们第一次先定好首个数字 1 ,然后求 [2,3] 的全排列,对于 [2,3] 的全排列,又可以采取定好首个字母来确定,以此类推,将首数字为 1 的情况列举完以后,在查看其他的情况。

我们可以用这道题,详细分析一下回溯算法,回溯算法可以有如下模板,时间复杂度为O(n2):

result = []
func backtrack(路径,选择列表) {
	if 满足结束条件 {
		result.add(路径)
	}
	return

	for 选择 in 选择列表 {
		做选择
		backtrack(路径,选择列表)
		撤销选择
	}
}

我们用模板,则有以下算法可以:

var result [][]int

func permute(nums []int) [][]int {
    //先设定最后结果,路径和被使用过的数字
    result = [][]int{} 
    pathNums := []int{} 
    used := make([]bool, len(nums)) 
    backtrack(nums, pathNums, used)
    return result
}

func backtrack(nums, pathNums []int, used []bool) {
    //设定结束条件,当走完这个数列是,回溯结束
    if len(nums) == len(pathNums) { 
        tmp := make([]int, len(nums))
        //只使用公用数据
        copy(tmp, pathNums)
        result = append(result, tmp)
        return
    }

    for i:=0; i<len(nums); i++ {
        //设定判断,若未使用,进入内部并标记此数字被使用
        if !used[i] {
            used[i] = true 
            //将数字放入尾部,
            pathNums = append(pathNums, nums[i]) 
            //继续搜索
            backtrack(nums, pathNums, used) 
            //撤销一步
            pathNums = pathNums[:len(pathNums)-1] 
            //标记为未使用
            used[i] = false 
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值