返回

巧用交换技巧,全排列 II 无重复

前端

引言

在计算机科学领域,全排列是一个重要的概念,它指将一个集合中的元素按任意顺序排列的所有可能组合。然而,当集合中包含重复元素时,全排列的过程变得更加复杂。本文将探讨如何解决 LeetCode 47:全排列 II 这道题目,它要求我们找出包含重复数字序列的所有不重复全排列。

算法剖析

解决全排列 II 问题的关键在于避免生成重复的全排列。为此,我们可以使用回溯法并结合交换技巧。

  1. 回溯法:

    回溯法是一种算法策略,它通过系统地探索所有可能的状态并逐层回溯来解决问题。在这个问题中,我们将使用回溯来生成所有可能的排列,并将重复的排列标记为已访问。

  2. 交换技巧:

    为了避免生成重复的全排列,我们可以使用交换技巧。在每次递归调用中,我们首先将当前元素与它后面的所有唯一元素进行交换,然后再进行递归调用。这确保了每个元素仅出现在其应出现的位置。

步骤分解

  1. 初始化:

    • 创建一个空列表 result 来存储结果。
    • 创建一个布尔数组 visited 来标记元素是否已被访问。
    • 设置初始交换索引 start 为 0。
  2. 递归函数:

    def backtrack(start, nums):
        # 如果 start 超出范围,则添加排列到结果中
        if start == len(nums) - 1:
            result.append(nums.copy())
            return
    
        for i in range(start, len(nums)):
            # 如果元素未被访问
            if not visited[i]:
                # 交换元素
                nums[start], nums[i] = nums[i], nums[start]
                # 标记元素已访问
                visited[i] = True
                # 递归调用
                backtrack(start + 1, nums)
                # 回溯
                visited[i] = False
                # 还原交换
                nums[start], nums[i] = nums[i], nums[start]
    
  3. 主函数:

    def permuteUnique(nums):
        # 初始化
        result = []
        visited = [False] * len(nums)
    
        # 按升序对 nums 排序
        nums.sort()
    
        # 调用递归函数
        backtrack(0, nums)
    
        return result
    

代码实现

def permuteUnique(nums):
    result = []
    visited = [False] * len(nums)

    nums.sort()

    def backtrack(start, nums):
        if start == len(nums) - 1:
            result.append(nums.copy())
            return

        for i in range(start, len(nums)):
            if not visited[i]:
                nums[start], nums[i] = nums[i], nums[start]
                visited[i] = True
                backtrack(start + 1, nums)
                visited[i] = False
                nums[start], nums[i] = nums[i], nums[start]

    backtrack(0, nums)
    return result

总结

通过巧用交换技巧和回溯法,我们成功解决了 LeetCode 47:全排列 II 这道题目。这种方法有效地避免了生成重复的全排列,确保了结果的准确性和效率。理解此算法对于解决更复杂的全排列问题至关重要。