回溯简介:
程序在运行过程中分成了多个阶段。
通过某些手段,将数据恢复到之前某一阶段,这就称之为回溯。
手段包括: ①方法栈 ②自定义栈
比如给数字1, 2, 3进行全排列。我们可以先固定数字1, 对2,3进行排列;然后固定2,对1,3进行排列;最后固定3,对1,2进行排列。
在代码实现时,我们需要准备两个数组,一个代表原始数组【1,2,3】,另一个数组,用来表示数字是否已固定(被使用过),已固定用灰色表示,未固定绿色表示。是个boolean变量。
比如说一开始固定1,同时把固定好的元素加入集合中,集合中就存储着我们的排列。紧接着固定2,最后剩下3,然后固定3。形成一种排列,只要集合的大小和数组长度一致时,就表示找到了其中一种排列。
然后我们需要用回溯法把数据恢复到有几个元素没有被固定的状态,继续找其他排列。依此类推。
找到其他排列如下图。
注意:
以上方法只适用于无重复元素的全排列。
代码实现:
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
public class PermuteLeetcode46 {
public static void main(String[] args) {
List<List<Integer>> permute = permute(new int[]{1, 2, 3});
for (List<Integer> s : permute) {
System.out.println(s);
}
}
public static List<List<Integer>> permute(int[] nums) {
List<List<Integer>> result = new ArrayList<>();
dfs(nums, new boolean[nums.length], new LinkedList<>(), result);
return result;
}
public static void dfs(int[] nums, boolean[] visited, LinkedList<Integer> stack, List<List<Integer>> result){
if(stack.size() == nums.length){
result.add(new ArrayList<>(stack)); //stack中的元素会不断变化,要把它里面的元素放入一个新集合
return;
}
for (int i = 0; i < nums.length; i++) {
if (!visited[i]) {
stack.push(nums[i]);
visited[i] = true;
dfs(nums, visited, stack, result);
visited[i] = false;
stack.pop();
}
}
}
}