1.回溯:组合总和
class Solution {
List<List<Integer>> res=new LinkedList<>();
public List<List<Integer>> combinationSum(int[] candidates, int target) {
if(candidates==null || candidates.length==0){
return res;
}
LinkedList<Integer> track=new LinkedList<>();
backTrack(candidates,target,track,0,0);
return res;
}
public void backTrack(int[] candidates, int target,LinkedList<Integer> track,int sum,int start){
if(sum==target){
res.add(new LinkedList(track));
return;
}
for(int i=start;i<candidates.length;i++){
if(sum+candidates[i]<=target){
track.add(candidates[i]);
sum+=candidates[i];
backTrack(candidates,target,track,sum,i);
track.removeLast();
sum-=candidates[i];
}
}
}
}
2.回溯:字符串的排列
class Solution {
Set<String> set=new HashSet<>();
public String[] permutation(String s) {
if(s==null || s.length()==0){
return new String[0];
}
StringBuilder sb=new StringBuilder();
boolean[] used=new boolean[s.length()];
backTrack(s,sb,used);
String[] res=new String[set.size()];
int index=0;
for(String s1:set){
res[index]=s1;
index++;
}
return res;
}
public void backTrack(String s,StringBuilder sb,boolean[] used){
if(sb.length()==s.length()){
set.add(new String(sb.toString()));
return;
}
for(int i=0;i<s.length();i++){
if(used[i]) continue;
sb.append(s.charAt(i));
used[i]=true;
backTrack(s,sb,used);
sb.deleteCharAt(sb.length()-1);
used[i]=false;
}
}
}
3.回溯:组合总和2
class Solution {
List<List<Integer>> res=new LinkedList<>();
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
if(candidates==null || candidates.length==0){
return res;
}
LinkedList<Integer> track=new LinkedList<>();
boolean[] used=new boolean[candidates.length];
Arrays.sort(candidates);
backTrack(candidates,target,track,0,0,used);
return res;
}
public void backTrack(int[] candidates, int target,LinkedList<Integer> track,int start,int sum,boolean[] used){
if(sum==target){
res.add(new LinkedList(track));
return;
}
for(int i=start;i<candidates.length;i++){
if(i>0 && candidates[i-1]==candidates[i] && !used[i-1]){
continue;
}
if(sum+candidates[i]<=target){
track.add(candidates[i]);
sum+=candidates[i];
used[i]=true;
backTrack(candidates,target,track,i+1,sum,used);
track.removeLast();
sum-=candidates[i];
used[i]=false;
}
}
}
}
4.回溯:分割回文串
class Solution {
List<List<String>> res=new LinkedList<>();
public List<List<String>> partition(String s) {
if(s==null || s.length()==0){
return res;
}
LinkedList<String> track=new LinkedList<>();
backTrack(s,track,0);
return res;
}
//count用于统计已经加进track里面的字符的总个数,用于判断是否当前track已经满足加进res的条件
public void backTrack(String s,LinkedList<String> track,int index){
if(index==s.length()){
res.add(new LinkedList(track));
return;
}
for(int i=index;i<s.length();i++){
if(!isHuiWen(s,index,i)){
continue;
}
track.add(s.substring(index,i+1));
backTrack(s,track,i+1);
track.removeLast();
}
}
public boolean isHuiWen(String s,int left,int right){
while(left<right){
if(s.charAt(left)!=s.charAt(right)){
return false;
}
left++;
right--;
}
return true;
}
}
5.回溯:所有可能的路径
class Solution {
List<List<Integer>> res=new LinkedList<>();
public List<List<Integer>> allPathsSourceTarget(int[][] graph) {
if(graph==null || graph.length==0){
return res;
}
LinkedList<Integer> track=new LinkedList<>();
backTrack(0,graph,track);
return res;
}
public void backTrack(int index,int[][] graph,LinkedList<Integer> track){
track.add(index);//index是下一个要访问的值
//如果index恰好等于n-1,则这是一条能够到达n-1的路径,则将这条路径添加到结果列表中
if(index==graph.length-1){
res.add(new LinkedList(track));
return;
}
//比如已经添加了值为2的节点,即index=2,那么接下来就要去遍历值为2那个节点所能到达的位置,判断其能否到达终点
for(int i=0;i<graph[index].length;i++){
backTrack(graph[index][i],graph,track);
track.removeLast();
}
}
}
6.回溯:子集2
class Solution {
List<List<Integer>> res=new LinkedList<>();
public List<List<Integer>> subsetsWithDup(int[] nums) {
if(nums==null || nums.length==0){
return res;
}
//遇到这种带有重复值的,解集中不能重复的,则需要先排序,并定义一个used数组记录使用过的位置,后续再进行剪枝
Arrays.sort(nums);
boolean[] used=new boolean[nums.length];
LinkedList<Integer> track=new LinkedList<>();
//需要一个位置索引start限制下次遍历从下个位置开始
backTrack(nums,track,0,used);
return res;
}
public void backTrack(int[] nums,LinkedList<Integer> track,int start,boolean[] used){
res.add(new LinkedList(track));
for(int i=start;i<nums.length;i++){
//遇到重复值跳过
if(i>0 && nums[i-1]==nums[i] && !used[i-1]){
continue;
}
track.add(nums[i]);
used[i]=true;
backTrack(nums,track,i+1,used);
track.removeLast();
used[i]=false;
}
}
}
7.回溯:不同路径3
class Solution {
int res=0;
public int uniquePathsIII(int[][] grid) {
if(grid==null || grid.length==0){
return res;
}
//记录走过哪些位置,不要重复走
boolean[][] used=new boolean[grid.length][grid[0].length];
//找到起始位置
int start_i=0,start_j=0;
//0的个数num_zero,从起点到终点走的步数应该是num_zero+1
int num_zero=0;
for(int i=0;i<grid.length;i++){
for(int j=0;j<grid[0].length;j++){
if(grid[i][j]==1){
start_i=i;
start_j=j;
}
if(grid[i][j]==0){
num_zero++;
}
}
}
//从起始位置开始递归遍历
backTrack(grid,used,start_i,start_j,num_zero,0);
return res;
}
//(i,j)表示正在遍历的位置,step为走过的步数
public void backTrack(int[][] grid,boolean[][] used,int i,int j,int num_zero,int step){
//1.进行当前位置合法性判断
if(i<0 || j<0 || i>=grid.length || j>=grid[0].length || used[i][j] || grid[i][j]==-1){
return;
}
//2.判断是否到达终点,如果到达,则是一个有效路径,res+1
if(grid[i][j]==2 && step==num_zero+1){
res++;
return;
}
//3.走到当前位置,然后对当前位置的四个方向进行递归
used[i][j]=true;
backTrack(grid,used,i+1,j,num_zero,step+1);
backTrack(grid,used,i,j+1,num_zero,step+1);
backTrack(grid,used,i-1,j,num_zero,step+1);
backTrack(grid,used,i,j-1,num_zero,step+1);
used[i][j]=false;
}
}