LeetCode——0046.全排列

46.全排列

题目

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

示例:

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

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

题解思路

1>源代码

class Solution:
    def permute(self, nums):
        def back(first=0):
            if(first == len(nums)):
                res.append(nums[:])
                return
            for i in range(first, len(nums)):
                nums[first], nums[i] = nums[i], nums[first]
                back(first+1)
                nums[first], nums[i] = nums[i], nums[first]

        res = []
        back()
        return res

2>算法介绍

这道题对于第一次遇见的我来说​,还是有些没思路。对于我们人类来说很轻而易举的事情,要想交给机器来完成还是需要精心设计算法。这道题是一道经典的回溯算法题。

按照我们人类的思路,全排列[1,2,3]的思路大概是这样:

  1. 以1作为第一个元素,排列2,3。得到结果[1,2,3],[1,3,2]
  2. 以2作为第一个元素,排列1,3。得到结果[2,1,3],[2,3,1]
  3. 以3作为第一个元素,排列1,2。得到结果[3,1,2],[3,2,1]

对于上述的状态1来说,你在排列2,3的时候,得到了排列后的序列1,2,3,你会发现这时这个序列已经排列完成了,这时候你就需要回溯到上一状态,那就是1作为第一个元素的状态,再去寻找此时的第二个元素应该是什么。

我们再举一个更普遍的例子,假设我们要全排列序列[3,4,5,6,7,8],在某一时刻我们已经排列到了[6,7, | 3,4,5,8]的情况,表示当前状态下,|左侧的元素位置不再变化。那么如果接下来我想从[6,7,8, |3,4,5]这个状态开始尝试,那么我们就应该把8和3的位置对调,并且将 | 向右移动。这也就是我们递归的设置思路。在你尝试完这种状态的所有排列后,别忘了进行复原,也就是将本例中将8和3的位置调换回来。

如果上述描述还不足以理解的话,我们不妨思考一下第一次递归退出点。第一次递归所获得的排列一定是原列表顺序,因为back()会不断递归进去直到最后一个元素。对于例子[1,2,3]来说,递归退出后,此时的first=1,i=2,交换两者对应的值会得到排列[1,3,2]。在输出排列后会将这两个值再换回来,并退出此时的递归。

退出递归后,first=0,i=1,交换两者对应的值得到[2,1,|3],也即[2,1,3],接下来的步骤就很好理解了。

实话说,这种题目第一次遇到还是有难度,设计递归本身就是一件比较抽象的事情,还是需要多多练习。

你可能感兴趣的:(LeetCode训练,leetcode,算法)