力扣top100-46.全排列-节省visit辅助数组的开销
背景
在访问元素的时候,经常会用到一个辅助数组visit[nums.length]来记录元素的访问状态
特别是在图,树的深度遍历,要记录元素是否已经访问过了
在答案树的回溯过程中,经常需要剪枝来删除一些答案,比如要求是不重复的元素
问题
那么使用visit数组,会开辟额外的空间
解决
那么能不能考虑使用原地数组来记录访问情况,
在原地使用nums[],唯一的办法就是在nums[]中划分一个位置index,左面的代表已经访问过的,右边代表还未访问过的
同时这个位置也能代表答案树的回溯深度
具体例子
链接:https://leetcode-cn.com/problems/permutations
给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。
示例 1:
输入:nums = [1,2,3]
输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
示例 2
输入:nums = [0,1]
输出:[[0,1],[1,0]]
示例 3:
输入:nums = [1]
输出:[[1]]
分析:
正常情况是一个暴力破解的答案树,然后剪枝其中的不符合情况(有重复元素)
那么就要设置一个访问数组,每次回溯前设置已访问,方法返回后再设置成未访问
可以通过将nums划分为两部分,左边代表着已经访问过,右边代表着还未访问,
怎么确定哪些访问了呢,很简单,设置一个index,左边访问了,右边没访问
访问下一个就让index右移,回溯就左移
但是,涉及到回溯,每次回完了,怎么跳到下一个呢,那么nums就不能保持不变,每次可以交换index位置和后面的元素
注意,回溯完了,别忘了换回去
与一般回溯的栈不同的是,这道题开始就直接将所有元素都压进去,然后通过
代码
public List> permute(int[] nums) {
List> res=new ArrayList<>();
List A=new ArrayList<>();
for (int i = 0; i < nums.length; i++) {
A.add(nums[i]);
}
Stack(nums.length,A,res,0);
return res;
}
public void Stack(int len,List A, List> res,int index){
if(index==len){
res.add(new ArrayList<>(A));
}
for (int i = index; i < len; i++) {
Collections.swap(A,index,i);
Stack(len,A,res,index+1);
Collections.swap(A,index,i);
}
}