leetcode 47. 全排列 II

121 阅读1分钟

[toc] leetcode 47. 全排列 II

题目描述

  1. 全排列 II

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

示例 1:

输入:nums = [1,1,2] 输出: [[1,1,2], [1,2,1], [2,1,1]] 示例 2:

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

提示:

1 <= nums.length <= 8 -10 <= nums[i] <= 10

解题思路

法1

排序+回溯

我们的核心还是之前的回溯算法,向下逐步确定每一个位置的字符,

但是不同的是这里有重复的字符,在同一个位置只能出现不同相同的字符,如果有相同的字符,出现过就不能再次出现,应该跳过,

比如abcdc,那么第一个位置可以是a,b,c,d;其中c出现了两次,只能需要跳过一次,

我们可以使用两个方案实现已经出现过的字符的跳跃

  1. 哈希表:map[byte]bool,来判断是否出现过
  2. 排序,将字符进行排序,相同的字符就会在一起,这样就可以通过判断前后位置的字符是否相同方法进行已经出现过的字符跳跃

递归确定每一个位置的这么,直到确定最后一个位置,统计所有出现的情况,输出结果

  • 时间复杂度(O(n^2))
  • 空间复杂度(O(n))

执行结果

法1

我们首先对给定的 nums 序列进行排序,这样可以确保相同的数字相邻。然后,我们使用回溯函数 backtrack() 来生成不重复的全排列。回溯函数采用递归的方式,对每个位置进行选择,并使用 visited 数组来记录已经访问过的元素,以避免重复。

在主函数中,我们定义了一个示例序列 nums = [1, 1, 2],然后调用 permuteUnique() 函数来获取所有不重复的全排列,并将结果打印输出。


func permuteUnique(nums []int) [][]int {
	var result [][]int
	visited := make([]bool, len(nums))
	current := []int{}
	sort.Ints(nums)
	backtrack(nums, visited, current, &result)
	return result
}

func backtrack(nums []int, visited []bool, current []int, result *[][]int) {
	if len(current) == len(nums) {
		temp := make([]int, len(nums))
		copy(temp, current)
		*result = append(*result, temp)
		return
	}

	for i := 0; i < len(nums); i++ {
		if visited[i] || (i > 0 && nums[i] == nums[i-1] && !visited[i-1]) {
			continue
		}

		visited[i] = true
		current = append(current, nums[i])
		backtrack(nums, visited, current, result)
		current = current[:len(current)-1]
		visited[i] = false
	}
}

执行结果: 通过 显示详情 查看示例代码 添加备注

执行用时: 0 ms , 在所有 Go 提交中击败了 100.00% 的用户 内存消耗: 3.6 MB , 在所有 Go 提交中击败了 50.28% 的用户 通过测试用例: 33 / 33 炫耀一下:

优化:

首先,我们可以使用一个map来记录每个数字的出现次数,以避免排序操作。这样可以在遍历时动态地选择可用的数字。

其次,我们可以使用一个slice来存储剩余可选数字的索引,而不是使用visited数组来跟踪访问过的数字。这样可以简化代码并减少额外的数组操作。

func permuteUnique(nums []int) [][]int {
	var result [][]int
	countMap := make(map[int]int)
	for _, num := range nums {
		countMap[num]++
	}
	current := []int{}
	backtrack(nums, countMap, current, &result)
	return result
}

func backtrack(nums []int, countMap map[int]int, current []int, result *[][]int) {
	if len(current) == len(nums) {
		temp := make([]int, len(nums))
		copy(temp, current)
		*result = append(*result, temp)
		return
	}

	for num, count := range countMap {
		if count == 0 {
			continue
		}

		countMap[num]--
		current = append(current, num)
		backtrack(nums, countMap, current, result)
		current = current[:len(current)-1]
		countMap[num]++
	}
}

本文由mdnice多平台发布