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 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

这道题目是求集合,并不是 求极值,因此动态规划不是特别切合,因此我们需要考虑别的方法。

这种题目其实有一个通用的解法,就是回溯法。网上也有大神给出了这种回溯法解题的 通用写法https://leetcode.com/problems/combination-sum/discuss/16502/A-general-approach-to-backtracking-questions-in-Java-(Subsets-Permutations-Combination-Sum-Palindrome-Partitioning),这里的所有的解法使用通用方法解答。除了这道题目还有很多其他题目可以用这种通用解法,具体的题目见后方相关题目部分。

我们先来看下通用解法的解题思路,我画了一张图:

640?wx_fmt=png

通用写法的具体代码见下方代码区。

关键点解析

  • 回溯法

  • backtrack 解题公式

代码

  • 语言支持: Javascript, Python3

Javascript Code:

/*	
 * @lc app=leetcode id=46 lang=javascript	
 *	
 * [46] Permutations	
 *	
 * https://leetcode.com/problems/permutations/description/	
 *	
 * algorithms	
 * Medium (53.60%)	
 * Total Accepted:    344.6K	
 * Total Submissions: 642.9K	
 * Testcase Example:  '[1,2,3]'	
 *	
 * Given a collection of distinct integers, return all possible permutations.	
 *	
 * Example:	
 *	
 *	
 * Input: [1,2,3]	
 * Output:	
 * [	
 * ⁠ [1,2,3],	
 * ⁠ [1,3,2],	
 * ⁠ [2,1,3],	
 * ⁠ [2,3,1],	
 * ⁠ [3,1,2],	
 * ⁠ [3,2,1]	
 * ]	
 *	
 *	
 */	
function backtrack(list, tempList, nums) {	
    if (tempList.length === nums.length) return list.push([...tempList]);	
    for(let i = 0; i < nums.length; i++) {	
        if (tempList.includes(nums[i])) continue;	
        tempList.push(nums[i]);	
        backtrack(list, tempList, nums);	
        tempList.pop();	
    }	
}	
/**	
 * @param {number[]} nums	
 * @return {number[][]}	
 */	
var permute = function(nums) {	
    const list = [];	
    backtrack(list, [], nums)	
    return list	
};

Python3 Code:

class Solution:	
    def permute(self, nums: List[int]) -> List[List[int]]:	
        """itertools库内置了这个函数"""	
        return itertools.permutations(nums)	
    def permute2(self, nums: List[int]) -> List[List[int]]:	
        """自己写回溯法"""	
        res = []	
        def _backtrace(nums, pre_list):	
            if len(nums) <= 0:	
                res.append(pre_list)	
            else:	
                for i in nums:	
                    # 注意copy一份新的调用,否则无法正常循环	
                    p_list = pre_list.copy()	
                    p_list.append(i)	
                    left_nums = nums.copy()	
                    left_nums.remove(i)	
                    _backtrace(left_nums, p_list)	
        _backtrace(nums, [])	
        return res

Python Code:

class Solution:	
    def permute(self, nums: List[int]) -> List[List[int]]:	
        """itertools库内置了这个函数"""	
        import itertools	
        return itertools.permutations(nums)	
    def permute2(self, nums: List[int]) -> List[List[int]]:	
        """自己写回溯法"""	
        res = []	
        def _backtrace(nums, pre_list):	
            if len(nums) <= 0:	
                res.append(pre_list)	
            else:	
                for i in nums:	
                    # 注意copy一份新的调用,否则无法正常循环	
                    p_list = pre_list.copy()	
                    p_list.append(i)	
                    left_nums = nums.copy()	
                    left_nums.remove(i)	
                    _backtrace(left_nums, p_list)	
        _backtrace(nums, [])	
        return res	
    def permute3(self, nums: List[int]) -> List[List[int]]:	
        """回溯的另一种写法"""	
        res = []	
        length = len(nums)	
        def _backtrack(start=0):	
            if start == length:	
                # nums[:] 返回 nums 的一个副本,指向新的引用,这样后续的操作不会影响已经已知解	
                res.append(nums[:])	
            for i in range(start, length):	
                nums[start], nums[i] = nums[i], nums[start]	
                _backtrack(start+1)	
                nums[start], nums[i] = nums[i], nums[start]	
        _backtrack()	
        return res

相关题目

  • 31.next-permutation

  • 39.combination-sum

  • 40.combination-sum-ii

  • 47.permutations-ii

  • 60.permutation-sequence(TODO)

  • 78.subsets

  • 90.subsets-ii

  • 113.path-sum-ii

  • 131.palindrome-partitioning

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值