现象:
基础算法-回溯算法-案例
- 基础算法-回溯算法
- 从不同角度出发 去寻找答案 找到答案或者走不通了(根据需求:找一个答案还是列举全部答案) 则回溯返回
- 继续从下一条路出发 去寻找答案, 一直到走完
常见案例:
案例一:
通过输入一个不重复数组如:[1,2,3]
使用数组中的元素不重复排列组成不同数组如 {1,2,3}{1,3,2},{2,1,3},{2,3,1},{3,1,2},{3,2,1}
- 思路:
- 第一步: 第一层: 先循环数组,将数组第一个元素放临时list,临时数组=[1]
- 第二步: 递归调用在第二层, 在循环中,数组中下一个不重复元素放入临时数组,临时数组=[1,2]
- 第四步: 递归调用在第三层, 在循环中,数组中下一个不重复元素放入临时数组,临时数组=[1,2,3] 此时第三次迭代的循环已经走完
- 第五步: 递归调用在第四层, 此时判断临时数组的长度满足要求了,将临时数组结果放最终结果集,跳出这次递推,回到第三层递推函数
- 第六步: 回到第三层, 此时循环已经走完,执行第三层的回溯删除,移除临时数组最后一个元素,临时数组=[1,2] 此时第三层迭代函数走完
- 第七步: 回到第二层, 执行回溯删除,移除数组最后一个元素,临时数组=[1]
- 第八步: 第二层, 循环继续,在循环中,数组中下一个元素放临时数组,临时数组=[1,3]
- 第九步: 递归调用进入第三层, 在循环中,数组下一个不重复元素放入临时数组,临时数组=[1,3,2]
- 第十步: 递归调用进入第四层, 此时判断临时数组的长度满足要求了,将临时数组结果放最终结果集,跳出这次递推,回到第三层递推函数
- 第十一步: 回到第三层, 此时循环已经走完,执行第三层的回溯删除,移除临时数组最后一个元素,临时数组=[1,3] 此时第三层迭代函数走完
- 第十二步: 回到第二层, 执行回溯删除,移除数组最后一个元素,临时数组=[1],此时第二层函数循环走完
- 第十三步: 回到第一层, 执行回溯删除,移除数组最后一个元素,临时数组=[0] 此时完成了第一层的第一次迭循环,临时数组也清空了
- 第十四步: 第一层: 继续执行第一层的循环,将数组第二个元素放list 临时数组=[2]
- 继续执行第二…到…第十三步 一直到最外层循环走完,所有结果都将存放在结果集,临时数组也清空状态
代码方法:
/** 最终结果存放容器 */
static List<List<Integer>> result = new ArrayList<>();
public static void main(String[] args){
int[] a ={1,2,3};
arrList(a, new ArrayList<>());
for (List<Integer> list: result) {
log.debug("list:{}",list);
}
}
/**
* 通过输入一个不重复数组
* 使用数组中的元素不重复排列组成不同数组
*
* 思路:
* 第一步: 第一层: 先循环数组,将数组第一个元素放临时list,临时数组=[1]
* 第二步: 递归调用在第二层, 在循环中,数组中下一个不重复元素放入临时数组,临时数组=[1,2]
* 第四步: 递归调用在第三层, 在循环中,数组中下一个不重复元素放入临时数组,临时数组=[1,2,3] 此时第三次迭代的循环已经走完
* 第五步: 递归调用在第四层, 此时判断临时数组的长度满足要求了,将临时数组结果放最终结果集,跳出这次递推,回到第三层递推函数
* 第六步: 回到第三层, 此时循环已经走完,执行第三层的回溯删除,移除临时数组最后一个元素,临时数组=[1,2] 此时第三层迭代函数走完
* 第七步: 回到第二层, 执行回溯删除,移除数组最后一个元素,临时数组=[1]
* 第八步: 第二层, 循环继续,在循环中,数组中下一个元素放临时数组,临时数组=[1,3]
* 第九步: 递归调用进入第三层, 在循环中,数组下一个不重复元素放入临时数组,临时数组=[1,3,2]
* 第十步: 递归调用进入第四层, 此时判断临时数组的长度满足要求了,将临时数组结果放最终结果集,跳出这次递推,回到第三层递推函数
* 第十一步: 回到第三层, 此时循环已经走完,执行第三层的回溯删除,移除临时数组最后一个元素,临时数组=[1,3] 此时第三层迭代函数走完
* 第十二步: 回到第二层, 执行回溯删除,移除数组最后一个元素,临时数组=[1],此时第二层函数循环走完
* 第十三步: 回到第一层, 执行回溯删除,移除数组最后一个元素,临时数组=[0] 此时完成了第一层的第一次迭循环,临时数组也清空了
*
* 第十四步: 第一层: 继续执行第一层的循环,将数组第二个元素放list 临时数组=[2]
* 继续执行第二...到...第十三步 一直到最外层循环走完,所有结果都将存放在结果集,临时数组也清空状态
*
*/
public static void arrList(int[] arr, List<Integer> list){
// 定义一个临时list 接受入参list
List<Integer> tempList=new ArrayList<>(list);
if(tempList.size()==arr.length){
// 临时list长度满足要求了 放最终结果集
result.add(tempList);
// 返回这次递归 回到上次递归的循环中 执行上一层回溯remove删除方法
return;
}
for (int i=0;i<=arr.length-1;i++){
// 控制元素不能重复
if(tempList.contains(arr[i])){
continue;
}
tempList.add(arr[i]);
// 递归调用
arrList(arr,tempList);
// 回溯关键:每次循环走完 就开始逐步减少最后一个元素
tempList.remove(tempList.size()-1);
}
结果: