力扣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<List<Integer>> permute(int[] nums) {
	List<List<Integer>> res=new ArrayList<>(); 
	List<Integer> 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<Integer> A, List<List<Integer>> 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);
	}
}
posted @ 2022-03-06 19:37  荧惑微光  阅读(38)  评论(0编辑  收藏  举报