Introduction to Backtracking
Have you ever run into these problems in your daily life?
- For my luggage lock, what are some of the interesting password combination I can come up with? 🔐
- For my living room, how many possible ways I can rearrange my sofa, table, speakers and TV? 📺
- Or, yes! this is a good one, given a set of liquors and juice, what are possible cocktails I can come up with? 🍹
Backtracking
"Backtracking can be defined as a general algorithmic technique that considers searching every possible combination in order to solve a computational problem."
Intuitions of A Backtracking Problem
- The problem is about combinations, combinatorics, and permutation. Usually the problem has multiple possible solutions and it asks you to "list" or "enumerate" all the possible solutions.
- When you try to come up with an combination of both iteration and recursion. For example, you need to have a loop inside of a recursive function, and the loop's range depends on the function parameters:
void someRecursiveFunction(int x, int y){
/* do something... */
for(int i = 0; i < y; i++){
/* do something in the for loop... */
// call someRecursiveFunction with updated parameters
someRecursiveFunction(x, y+i);
}
/* do something else... */
}
- When you can prove that the solution needs a runtime of
Backtracking Generalized Solution Template
class Solution {
/* Declare private data structures: */
private ArrayList<Integer> solutions;
public List<List<Integer>> permute(int[] nums) {
// declare private data structures
solutions = new ArrayList<>();
// call backtrack
backtrack(param1, param2);
// return results
return this.results;
}
private void backtrack(int param1, int param2){
// handle base case!
if(BaseCase qualified){
// Add current result to the solution collection
solutions.add(param2)
return;
}
for(int i = 0; i< param1; i++){
// 1. Handle edge case
if(count[i] == 0) continue;
// 2. Prepare a possible solution using some variable
result.set(level, nums[i]);
// 3. Remove used variable in step 2
count[i]--;
// 4. Call backtrack recursively
backtrack(param1, param2+1);
// 5. Add used variable in step 2 and 4 back to the set
count[i]++;
}
}
}