1. 全排列(含重复元素去重)的回溯模板中 used 数组与同层剪枝的原理?
全排列(含重复元素去重)的回溯模板,说明 used 数组与同层剪枝的原理?
- 回溯模板:choose/explore/unchoose
- used 数组标记已选
- 同层剪枝去重
全排列回溯:递归选择每个位置,用 used 数组标记元素是否已被选。每层尝试所有未选元素,加入当前排列,递归下一层,返回后撤销(remove 最后 + used 置 false)。去重(含重复元素):先排序,同层剪枝——若当前元素与前一个元素相同,且前一个元素未被使用(说明前一个已被本层尝试过/或本层刚移除),则跳过,避免产生相同排列。即 if(i>0 && nums[i]==nums[i-1] && !used[i-1]) continue。原理:排序后相同元素相邻,同层只允许第一个相同元素进入,后续相同元素因"前已用"被剪枝,保证每个值只在该层出现一次。used 数组标记"跨层"的已选,同层剪枝标记"同层"的去重,两者配合。
used 数组管"深度"(每层不重复选同一元素),同层剪枝管"宽度"(同层不重复枚举相同值)。排序是去重前提。掌握"used + 同层剪枝"是含重复全排列/组合/子集去重的通用模板。
List<List<Integer>> res = new ArrayList<>();
void permute(int[] nums, int[] used, List<Integer> cur) {
if (cur.size() == nums.length) { res.add(new ArrayList<>(cur)); return; }
for (int i = 0; i < nums.length; i++) {
if (used[i] == 1) continue;
if (i > 0 && nums[i] == nums[i - 1] && used[i - 1] == 0) continue; // 同层剪枝
used[i] = 1; cur.add(nums[i]);
permute(nums, used, cur);
cur.remove(cur.size() - 1); used[i] = 0; // 撤销
}
}