全排列 II
难度:
标签:
题目描述
English description is not available for the problem. Please switch to Chinese.
代码结果
运行时间: 34 ms, 内存: 16.3 MB
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
/**
* 思路:
* 1. 使用回溯算法生成全排列。
* 2. 通过排序和判断跳过重复元素来避免重复的排列。
* 3. 使用Java Stream收集结果。
*/
public class Solution {
public List<List<Integer>> permuteUnique(int[] nums) {
List<List<Integer>> results = new ArrayList<>();
Arrays.sort(nums); // 排序以便于去重
boolean[] used = new boolean[nums.length];
backtrack(results, new ArrayList<>(), nums, used);
return results.stream().distinct().collect(Collectors.toList());
}
private void backtrack(List<List<Integer>> results, List<Integer> tempList, int[] nums, boolean[] used) {
if (tempList.size() == nums.length) {
results.add(new ArrayList<>(tempList));
} else {
for (int i = 0; i < nums.length; i++) {
if (used[i] || (i > 0 && nums[i] == nums[i-1] && !used[i - 1])) continue; // 跳过重复
used[i] = true;
tempList.add(nums[i]);
backtrack(results, tempList, nums, used);
used[i] = false;
tempList.remove(tempList.size() - 1);
}
}
}
}
解释
方法:
题解采用了回溯法来生成不重复的全排列。首先,将数组排序以方便后续步骤中的去重处理。定义一个递归函数 `backtrack(i)`,其中 `i` 表示当前固定元素的位置。在每次调用 `backtrack` 时,如果 `i` 等于数组长度,说明找到了一个全排列,将其添加到结果列表 `ans` 中。否则,使用一个集合 `used` 来记录在当前位置 `i` 已经尝试过的元素值,以避免生成重复的排列。对于每个从 `i` 到数组末尾的位置 `j`,如果该位置上的元素未被使用过,则将其与位置 `i` 的元素交换,并递归调用 `backtrack(i+1)`,完成更深层次的排列生成。递归完成后,再将元素交换回来,以便进行下一次的排列尝试。
时间复杂度:
O(n * n!)
空间复杂度:
O(n * n!)
代码细节讲解
🦆
为什么在实现'全排列 II'时需要先对数组进行排序?这对后续步骤有什么帮助?
▷🦆
在使用集合`used`记录已尝试过的元素时,其作用是什么?如何确保它有效地防止了重复排列的生成?
▷🦆
递归函数`backtrack(i)`中,当`i`等于`nums`的长度时直接将`nums[:]`添加到结果列表`ans`中,这里为什么要使用`nums[:]`而不是直接使用`nums`?
▷