文章目录
一、算法思想
回溯算法实际上是将多叉树结构的问题,采用类似枚举的方式,把问题的所有可能性全部罗列出来。当在搜索的过程中发现不满足给定条件的选项,就将该分支去掉,这个操作通常被称为“剪枝”,再回退到上一步(回溯),尝试别的路径,直到最后找完所有路径。
二、应用分类
- 排列问题:N个数按照一定规则全排列,有几种排列方式;
- 组合问题:N个数里面按一定规则找出K个数的集合;
- 切割问题:一个字符串按一定规则有几种切割方式;
- 子集问题:一个N个数的集合里有多少符合条件的子集;
- 棋盘问题:N皇后,岛屿问题;
三、经典例题
1. 排列问题
给定N个数或者长度为N的字符串,输出所有排列方式。排列问题输出的每一种排列方式长度都与原长度相等。
伪代码
void DFS(){
if(start == str.length-1){
//搜索到叶子节点
//去重判断
result.add(str); //存放结果
return;
}
for(i = start; i < str.length; i++){
//start下标用于缩小范围
swap(str,start,i); //处理节点
DFS(start+1); //下一层DFS
swap(str,start,i); //回溯
}
}
1.1 字符串的全排列
leetcode: 字符串的全排列
思路: 我们可以将字符串看成两部分,第一部分是以哪个字符开头,第二部分就是子问题。
定义一个start遍历字符串,使每个字符都做一遍开头,直到start 指向最后一个字符,说明已经当下已经排完,递归返回。
将start位置的字符分别和后面的所有字符进行交换(包括start位置)来实现不同的排列方式。
import java.util.ArrayList;
public class Solution {
public void swap(char[] str,int x,int y){
char temp = str[x];
str[x] = str[y];
str[y] = temp;
}
//当前这一步的处理逻辑
public void DFS(char[] str,int start, ArrayList<String> result){
//1. 退出条件
if(start == str.length - 1){
//valueOf(char[] data): 返回 char 数组参数的字符串表示形式
String s = String.valueOf(str);
//去重操作
if(!result.contains(s)){
//result.add(new String(str));
result.add(s);
return;
}
}
//2. 尝试当下的每一种可能,剪枝
for(int i = start; i < str.length; i++){
swap(str,i,start);
//3. 下一步DFS
DFS(str,start+1,result);
//4. 回溯
swap(str,i,start);
}
}
public ArrayList<String> Permutation(String str) {
ArrayList<String> result = new ArrayList<>(); //结果集
if(str.length() == 0) return result;
DFS(str.toCharArray(),0,result);
return result;
}
}
1.2 数组全排列
leetcode:数组全排列
思路: 与字符串排列大同小异,不过需要注意的是,本题的输入是数组,那么 1>
存入list中时需要遍历数组一个一个元素存进去,没有字符串操作方便,本题单独定义了一个arraylist方法来添加。 2>
数组进行去重操作也没有字符串便捷,所以将两个列表转换为字符串比较。当然去重方法很多,也可以用双重for循环,HashSet等。
class Solution {
public void swap(int[] nums,int x,int y){
int temp = nums[x];
nums[x] = nums[y];
nums[y] = temp;
}
public void arraylist(int[] nums,List<Integer> list){
for(int i = 0; i < nums.length; i++){
list.add(nums[i]);
}
}
public boolean isRepeat(List<List<Integer>> result,List<Integer> list){
String s = result.toString();
String l = list.toString();
return s.contains(l);
}
public void DFS(int[] nums,int start,List<Integer> list,List<List<Integer>> result){
if(start == nums.length-1){
if(!isRepeat(result,list))
result.add(new ArrayList<Integer> (list));
}
for (int i = start; i < nums.length; i++) {
swap(nums,i,start);
list.clear();
arraylist(nums,list);
DFS(nums,start+1,list,result);
swap(nums,i,start);
}
}
public List<List<Integer>> permute(int[] nums) {
List<List<Integer>> result = new ArrayList<>();
List<Integer> list = new ArrayList<>();
if(nums.length == 0) return result;
if(nums.length == 1) {
list.add(nums[