47. 全排列 II

题目描述

给定一个可包含重复数字的序列,返回所有不重复的全排列。

示例:

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

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

思路

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

这种题目其实有一个通用的解法,就是回溯法。网上也有大神给出了这种回溯法解题的 通用写法,这里的所有的解法使用通用方法解答。除了这道题目还有很多其他题目可以用这种通用解法,具体的题目见后方相关题目部分。

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

640?wx_fmt=png

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

关键点解析

  • 回溯法

  • backtrack 解题公式

代码

  • 语言支持: Javascript,Python3

/*	
 * @lc app=leetcode id=47 lang=javascript	
 *	
 * [47] Permutations II	
 *	
 * https://leetcode.com/problems/permutations-ii/description/	
 *	
 * algorithms	
 * Medium (39.29%)	
 * Total Accepted:    234.1K	
 * Total Submissions: 586.2K	
 * Testcase Example:  '[1,1,2]'	
 *	
 * Given a collection of numbers that might contain duplicates, return all	
 * possible unique permutations.	
 *	
 * Example:	
 *	
 *	
 * Input: [1,1,2]	
 * Output:	
 * [	
 * ⁠ [1,1,2],	
 * ⁠ [1,2,1],	
 * ⁠ [2,1,1]	
 * ]	
 *	
 *	
 */	
function backtrack(list, nums, tempList, visited) {	
  if (tempList.length === nums.length) return list.push([...tempList]);	
  for (let i = 0; i < nums.length; i++) {	
    // 和46.permutations的区别是这道题的nums是可以重复的	
    // 我们需要过滤这种情况	
    if (visited[i]) continue; // 不能用tempList.includes(nums[i])了,因为有重复	
    // visited[i - 1] 这个判断容易忽略	
    if (i > 0 && nums[i] === nums[i - 1] && visited[i - 1]) continue;	
    visited[i] = true;	
    tempList.push(nums[i]);	
    backtrack(list, nums, tempList, visited);	
    visited[i] = false;	
    tempList.pop();	
  }	
}	
/**	
 * @param {number[]} nums	
 * @return {number[][]}	
 */	
var permuteUnique = function(nums) {	
  const list = [];	
  backtrack(list, nums.sort((a, b) => a - b), [], []);	
  return list;	
};

Python3 code:

class Solution:	
    def permuteUnique(self, nums: List[int]) -> List[List[int]]:	
        """与46题一样,当然也可以直接调用itertools的函数,然后去重"""	
        return list(set(itertools.permutations(nums)))	
    def permuteUnique(self, nums: List[int]) -> List[List[int]]:	
        """自己写回溯法,与46题相比,需要去重"""	
        # 排序是为了去重	
        nums.sort()	
        res = []	
        def _backtrace(nums, pre_list):	
            if len(nums) <= 0:	
                res.append(pre_list)	
            else:	
                for i in range(len(nums)):	
                    # 如果是同样的数字,则之前一定已经生成了对应可能	
                    if i > 0 and nums[i] == nums[i-1]:	
                        continue	
                    p_list = pre_list.copy()	
                    p_list.append(nums[i])	
                    left_nums = nums.copy()	
                    left_nums.pop(i)	
                    _backtrace(left_nums, p_list)	
        _backtrace(nums, [])	
        return res

相关题目

  • 31.next-permutation

  • 39.combination-sum

  • 40.combination-sum-ii

  • 46.permutations

  • 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、付费专栏及课程。

余额充值