1. Backtracking
The backtracking algorithm is actually an enumeration-like search attempt, mainly to find a solution to the problem during the search attempt. When it finds that the solution condition has not been met, it "backtraces" back and tries another path.Backtracking is an optimal search method that searches forward according to the selection criteria to achieve the goal.However, when one step is explored and the original selection is found not good or fails to reach the goal, the technique of returning one step to another is backtracking, and the point of a state that meets the backtracking conditions is called backtracking point.
- If all the solutions need to be found, then each state needs to be searched.(function return value set to void)
- If a solution is required, it is sufficient to find one and return directly.(function return value set to boolean)
2. Algorithmic Framework
- Result Collection Conditions (Backtrace End Conditions)
- Continue to the next level of search criteria
- Search upper and lower bounds
//Algorithmic framework for finding all solutions public void backtracting(temp){ if("temp Is a result"){ //Result Collection Conditions //Join the result set; return; } for(j=start;j<= end;j++){ if("Not meeting the conditions for entry") continue; temp.add(a); //Add current element backtracting(j+1); //Continue with the next search temp.remove(a); //Backtracking cleanup, deleting the results of the previous step } } //Algorithmic Framework for Solving Existence public boolean backtracting(temp){ if("temp Is a result"){ //Result Collection Conditions //Join the result set; return true; } for(j=start;j<= end;j++){ if("Not meeting the conditions for entry") continue; temp.add(a); //Add current element if(backtracting(j+1)) return true; //Continue with the next search temp.remove(a); //Backtracking cleanup, deleting the results of the previous step return false; } }
3. General steps for solving problems by backtracking
(1) For a given problem, the solution space of the problem is determined: first, the solution space of the problem should be clearly defined, and the solution space of the problem should contain at least one (optimal) solution of the problem. (2) To determine the extended search rules for nodes, the search results must include the required solution. (3) Search the solution space in a depth-first manner and use the pruning function to avoid invalid searches (pruning occurs when solving problems).
4. Examples of common topics
77. Combinations
Given two integers n and k, return all possible combinations of k numbers out of 1 ... n.
For example,
If n = 4 and k = 2, a solution is:
[ [2,4], [3,4], [2,3], [1,2], [1,3], [1,4], ]
Title: Select k numbers from 1 - n as combinations to find out the specific sequence of all combinations.
Train of thought: Backtracking, traversing from the lower bound to the upper bound each time.If size() == k is satisfied, the result is added, and if all solutions are found, the traversal ends.Binary simulation can also be used.
public class Solution { List<List<Integer>> res = new LinkedList<List<Integer>>(); public List<List<Integer>> combine(int n, int k) { if(k==0) return res; helper(k,n,1,new LinkedList<Integer>()); return res; } public void helper(int k,int n,int start,List<Integer> out){ if(k<=0) return; if(k == out.size()){ List<Integer> temp = new LinkedList<Integer>(out); res.add(temp); return; } for(int i=start;i<=n;i++){ out.add(i); helper(k,n,i+1,out); //Because it's a combination, the elements are out of order, so each time you search from the next step out.remove(out.size()-1); } } }
39. Combination Sum
Given a set of candidate numbers (C) (without duplicates) and a target number (T), find all unique combinations in C where the candidate numbers sums to T.
The same repeated number may be chosen from C unlimited number of times.
Note:
- All numbers (including target) will be positive integers.
- The solution set must not contain duplicate combinations.
For example, given candidate set [2, 3, 6, 7] and target 7,
A solution set is:
[ [7], [2, 2, 3] ]
Title: Find the number of combinations in a set [without identical elements], and for a target.
Idea: Back-tracking, the collection condition is the target == 0 of the current sequence, the same as other combinations.
public class Solution { public List<List<Integer>> list = new LinkedList<List<Integer>>(); public List<List<Integer>> combinationSum(int[] candidates, int target) { if(candidates.length == 0) return list; helper(candidates,target,new LinkedList<Integer>(),0); return list; } public void helper(int[] candidates,int target,List<Integer> temp,int start){ //Maintain a target that represents the current sum, and 0 that the sum of temp elements equals the target. if(target<0) //For ease of judging collection conditions return; if(target == 0){ list.add(new LinkedList<Integer>(temp)); return; } for(int i=start;i<candidates.length;i++){ temp.add(candidates[i]); helper(candidates,target-candidates[i],temp,i); temp.remove(temp.size()-1); } } }
40. Combination Sum II
Given a collection of candidate numbers (C) and a target number (T), find all unique combinations in C where the candidate numbers sums to T.
Each number in C may only be used once in the combination.
Note:
- All numbers (including target) will be positive integers.
- The solution set must not contain duplicate combinations.
For example, given candidate set [10, 1, 2, 7, 6, 1, 5] and target 8,
A solution set is:
[ [1, 7], [1, 2, 5], [2, 6], [1, 1, 6] ]Title: Find a set with the same elements and the number of combinations for the target [combinations cannot be repeated].
Think: Add the same element to the conditional judgment before backtracking, but don't add it if it is the same.nums[i] == nums[i-1] continue;
public class Solution { public List<List<Integer>> list = new LinkedList<List<Integer>>(); public List<List<Integer>> combinationSum2(int[] candidates, int target) { Arrays.sort(candidates); if(candidates.length == 0) return list; helper(candidates,target,new LinkedList<Integer>(),0); return list; } public void helper(int[] candidates,int target,List<Integer> temp,int start){ if(target<0) return; if(target == 0){ list.add(new LinkedList<Integer>(temp)); return; } for(int i=start;i<candidates.length;i++){ if(i > start && candidates[i] == candidates[i-1]) continue; temp.add(candidates[i]); helper(candidates,target-candidates[i],temp,i+1); temp.remove(temp.size()-1); } } }
216. Combination Sum III
Find all possible combinations of k numbers that add up to a number n, given that only numbers from 1 to 9 can be used and each combination should be a unique set of numbers.
Example 1:
Input: k = 3, n = 7
Output:
[[1,2,4]]
Example 2:
Input: k = 3, n = 9
Output:
[[1,2,6], [1,3,5], [2,3,4]]
Think: Similar to the previous question, go back to lower bound 1, upper bound 9, and change the time limit for collection to temp.size() == K && target == 0
public class Solution { List<List<Integer>> res = new LinkedList<List<Integer>>(); public List<List<Integer>> combinationSum3(int k, int n) { if(k == 0){ return res; } hleper(n,k,1,new LinkedList<Integer>()); return res; } public void hleper(int sum,int k,int start,List<Integer> templist){ if(sum < 0) return; if(sum == 0 && templist.size()==k) { List<Integer> li = new ArrayList<Integer>(templist); res.add(li); return; } for(int i=start;i<=9;i++){ templist.add(i); hleper(sum-i,k,i+1,templist); templist.remove(templist.size()-1); } } }
46. Permutations
Given a collection of distinct numbers, return all possible permutations.
For example,
[1,2,3] have the following permutations:
[ [1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1] ]
Title: Find the full arrangement of 0 different numbers.
Think: 1. Backtracking searches deeply, every time from 0------- end, but you need a tag array to record which elements have been visited, elements added during backtracking and tags need to be cleared.
public class Solution { List<List<Integer>> res = new LinkedList<List<Integer>>(); public List<List<Integer>> permute(int[] nums) { if(nums.length == 0) return res; int[] temp = new int[nums.length+1]; helper(nums,new LinkedList<Integer>(),temp); return res; } public void helper(int[] nums,List<Integer> out,int[] visited){ if(nums.length == out.size()){ List<Integer> temp = new LinkedList<Integer>(out); res.add(temp); return; } for(int i=0;i<nums.length;i++){ if(visited[i] == 0){ visited[i]=1; out.add(nums[i]); helper(nums,out,visited); visited[i]=0; //Marker Cleanup out.remove(out.size()-1); //Temporary results backtracking } } } }
47. Permutations II
Given a collection of numbers that might contain duplicates, return all possible unique permutations.
For example,
[1,1,2] have the following unique permutations:
[ [1,1,2], [1,2,1], [2,1,1] ]Title: Give the elements with the same number, find the arrangement of all elements.
Idea: When nums[i] == nums[i-1], go directly to the next search, because if you do a deep search, the results will be repeated.That is, if the specific condition is defined.
public class Solution { public List<List<Integer>> list = new LinkedList<List<Integer>>(); public List<List<Integer>> permuteUnique(int[] nums) { Arrays.sort(nums); if(nums.length == 0) return list; int[] visited = new int[nums.length+1]; helper(nums,new LinkedList<Integer>(),visited); return list; } public void helper(int[] nums,List<Integer> temp,int[] visited){ if(temp.size() == nums.length){ list.add(new LinkedList<Integer>(temp)); return; } for(int i=0;i<nums.length;i++){ if (i>0 && nums[i]==nums[i-1]&&visited[i-1]==1) continue; //Specifically qualified nums[i-1]==nums[i] performs the next search, introducing a tag matrix. if(visited[i] == 0){ visited[i]=1; temp.add(nums[i]); helper(nums,temp,visited); visited[i]=0; temp.remove(temp.size()-1); } } } }
22. Generate Parentheses
Given n pairs of parentheses, write a function to generate all combinations of well-formed parentheses.
For example, given n = 3, a solution set is:
[ "((()))", "(()())", "(())()", "()(())", "()()()" ]Title: Find the full arrangement of all valid brackets
Ideas: For a legal permutation of length 2n, the first to 2n positions satisfy the following rules: The number of left parentheses is greater than or equal to the number of right parentheses
If left and right parentheses are left, then recursive solving can be divided into the following situations 1. left > 0 can continue to be bracketed 2. left=0 and right=0 result collection 3. Right>0 also needs to satisfy right>left to add right parentheses
public class Solution { public List<String> list = new LinkedList<String>(); public List<String> generateParenthesis(int n) { if(n == 0) return list; generate(n,n,"",list); return list; } public void generate(int left,int right,String res,List<String> list){ if(left == 0 && right == 0){ list.add(res); return; } if(left>0){ generate(left-1,right,res+"(",list); } if(right>0 && right>left){ generate(left,right-1,res+")",list); } } }78. Subsets
Given a set of distinct integers, nums, return all possible subsets.
Note: The solution set must not contain duplicate subsets.
For example,
If nums = [1,2,3], a solution is:[ [3], [1], [2], [1,2,3], [1,3], [2,3], [1,2], [] ]Title: Find a subset of a set that does not contain the same elementsIdeas: 1. Binary analogue operations, where each combination represents a binary (1 for fetch, 0 for no fetch).2. Backtracking is similar to combining, but the collection condition is changed to one collection without adding any
Collection conditions can also be considered if(true) collection;
//Binary analogue computation public class Solution { List<List<Integer>> res = new LinkedList<List<Integer>>(); public List<List<Integer>> subsets(int[] nums) { int n = nums.length; int count =1<<n; for(int i=0;i<count;i++){ List<Integer> temp = new LinkedList<Integer>(); int k=i; for(int j=0;j<n;j++){ int flag = k&1; k=k>>1; if(flag==0) temp.add(nums[j]); } res.add(temp); } return res; } }//Backtracking public class Solution { public List<List<Integer>> res = new LinkedList<List<Integer>>(); public List<List<Integer>> subsets(int[] nums) { if(nums.length == 0) return res; helper(new LinkedList<Integer>(),0,nums); return res; } public void helper(List<Integer> temp,int start,int[] nums){ res.add(new LinkedList<Integer>(temp)); for(int i=start;i<nums.length;i++){ temp.add(nums[i]); helper(temp,i+1,nums); temp.remove(temp.size()-1); } } }90. Subsets II
Given a collection of integers that might contain duplicates, nums, return all possible subsets.
Note: The solution set must not contain duplicate subsets.
For example,
If nums = [1,2,2], a solution is:[ [2], [1], [1,2,2], [2,2], [1,2], [] ]Title: Finding a subset of an array containing repeating elements cannot contain two identical subsets [different from the mathematical set].
Idea: Sort first, recursively move to the next level of condition nums[i]!= nums[i-1].
public class Solution { public List<List<Integer>> res = new LinkedList<List<Integer>>(); public List<List<Integer>> subsetsWithDup(int[] nums) { Arrays.sort(nums); if(nums.length == 0) return res; helper(new LinkedList<Integer>(),0,nums); return res; } public void helper(List<Integer> temp,int start,int[] nums){ res.add(new LinkedList<Integer>(temp)); for(int i=start;i<nums.length;i++){ if(i>start && nums[i]==nums[i-1]) continue; temp.add(nums[i]); helper(temp,i+1,nums); temp.remove(temp.size()-1); } } }526. Beautiful Arrangement
Suppose you have N integers from 1 to N. We define a beautiful arrangement as an array that is constructed by these N numbers successfully if one of the following is true for the ith position (1 ≤ i ≤ N) in this array:
- The number at the ith position is divisible by i.
- i is divisible by the number at the ith position.
Now given N, how many beautiful arrangements can you construct?
Example 1:
Input: 2 Output: 2 Explanation:Title: This question gives us 1 to N, a total of N positive numbers, and then defines a graceful arrangement. For all the numbers in this arrangement, if the number can divide the subscript, or the subscript can divide the number, then we are graceful arrangement, let's find the number of all graceful arrangements.
The first beautiful arrangement is [1, 2]:
Number at the 1st position (i=1) is 1, and 1 is divisible by i (i=1).
Number at the 2nd position (i=2) is 2, and 2 is divisible by i (i=2).
The second beautiful arrangement is [2, 1]:
Number at the 1st position (i=1) is 2, and 2 is divisible by i (i=1).
Number at the 2nd position (i=2) is 1, and i (i=2) is divisible by 1.
Ideas: pos represents subscripts, arranges complete, records the arrange position, visited or not accessed, and uses backtracking.Conditions for the next searchFor pos%i ==0 || i%pos == 0 && visited[i] = 0, it has not been accessed and can be collected.The collection condition is pso>n.public class Solution { int count = 0; public int countArrangement(int N) { if(N == 0) return 0; int[] visited = new int[N+1]; helper(visited,1,N); return count; } public void helper(int[] visited,int pos, int n){ if(pos>n){ count ++; return; } for(int i=1;i<=n;i++){ if(visited[i] == 0 && (pos%i==0 || i%pos==0)){ visited[i]=1; helper(visited,pos+1,n); visited[i]=0; } } } }