1. Problems that the backtracking search method can solve
(1) Combination problem : For example, there are several combinations of length 2 in 1, 2, 3, 4, 12, 13, 14, 23 , 24, 34. No order required
(2) Cutting problem : After talking about cutting a string, ensure that the cut substrings are all palindrome substrings.
(3) Subset problem : For example, all the subsets in 1, 2, 3, 4. No order required
(4) Arrangement problem : For example, several combinations of length 2 in 1, 2, 3, 4 are 12, 13, 14, 23 , 24, 34, 31, 21, 41, 32, 42 , 43. Need order.
(4) Checkerboard problem : n queen problem
It is difficult to solve the above-mentioned problems using loops, so the above-mentioned problems must be solved by the backtracking method.
2. The idea of backtracking search method
The backtracking method can be abstracted as a tree structure, and backtracking can be understood as a for loop of horizontal width and recursion of vertical depth of a tree.
3. The general routine of writing code (template)
public void backtracking()//define backtracking function
{
//1, termination conditions
if (termination condition)
{
Collect results;
return ;
}
//2, for loop execution processing node, recursive function, backtracking function
for (traversing collection elements)
{
Processing node
recursive function
Backtracking function
}
return the final traversal result.
}
4. Application of backtracking algorithm-combination problem
Ask the question first, take out all sets of length 2 in 1, 2, 3, and 4
code show as below:
for(int i=0;i<num.length;i++)
{
for (int j=i;j<num.length;j++)
{
System.out.print(i);
System.out.print(j);
}
}
But if we change the above array to a combination of 100 numbers and a length of 50, we need 50 levels of for loops to nest, which is obviously unrealistic.
At this time we need to perform a backtracking algorithm
Explain this figure, why every time you take a value, the following branches do not have this number, because the definition of combination is that the combination is in no order, so if you do not talk about the loss of the front array, it will inevitably cause data repeat.
Code
Recursive function parameter return value
Determine termination conditions
Single-level recursive function
Source code:
List<List<Integer>> result = new ArrayList<List<Integer>>();
List<Integer> path= new ArrayList<Integer>();
List<Integer> path2;
public List<List<Integer>> combine(int n, int k)
{
backstracking(n,k,1);
return result;
}
public void backstracking(int n,int k,int startindex)
{
if(path.size()==k)
{
path2=new ArrayList<Integer>();
for (int i: path)
{
path2.add(i);
}
result.add(path2);
return ;
}
for(int i=startindex;i<=n;i++)
{
path.add(i);
backstracking(n,k,i+1);//这里为什么是i+1呢因为不能出现两个字母的重复,如果是i的话就会出现11,22,33这种情况。
path.remove(path.size()-1);
}
}
5. Application of backtracking algorithm-pruning problem of combination problem
As shown in the figure below: if n=4 and k=4, a purely violent search will be a great waste of computer resources, so this algorithm needs to be optimized to make the time complexity of this algorithm lower.
The main thing to change is that size is changed to n-(k-path.size)+1;
6. Application of backtracking algorithm-combined sum
Scenes:
Given an array candidates with no duplicate elements and a target number target, find all combinations of candidates that can make the number sum target.
The number in candidates can be repeatedly selected without limitation.
Description:
All numbers (including target) are positive integers.
The solution set cannot contain repeated combinations.
Ideas:
Code writing ideas
Recursive function parameter return value
Determine termination conditions
Single-level recursive function
Source code:
import java.util.*;
class Solution {
public List<List<Integer>> combinationSum(int[] candidates, int target)
{
int sum=0;
int startindex=0;
backtracking(candidates,target,sum,startindex);
return result;
}
List<List<Integer>> result=new ArrayList<List<Integer>>();
List<Integer> path =new ArrayList<Integer>();
List<Integer> path2;
public void backtracking(int[] candidates, int target,int sum,int startindex)
{
//首先确定函数的参数以及返回值
if(sum>target)
{
return ;
}
//确定终止条件
if(sum==target)
{
path2=new ArrayList<Integer>();
for(int i: path)
{
path2.add(i);
}
result.add(path2);
return;
}
//确定单层递归函数
for(int i=startindex;i<candidates.length;i++)
{
path.add(candidates[i]);
sum=sum+candidates[i];
backtracking(candidates,target,sum,i);
sum=sum-candidates[i];
path.remove(path.size()-1);
}
return ;
}
}