diff --git a/think_like_computer/Details about Backtracking.md b/think_like_computer/Details about Backtracking.md index c98034571d89b0cef8ea3d5c3933f1ec6a0204c3..d8aec4243ad8ed94216f1f416273c731eb094caa 100644 --- a/think_like_computer/Details about Backtracking.md +++ b/think_like_computer/Details about Backtracking.md @@ -4,7 +4,7 @@ This article is an advanced version of "Details of Backtracking Algorithms" befo Ponder carefully and you will find that the backtracking problems follow the same pattern, that is, have the same framework. -Let's go straight to the framework backtracking follows. **Solving a backtracking problem is actually a traversal process of a decision tree. **Now you only need to think about 3 terms: +Let's go straight to the framework backtracking follows. **Solving a backtracking problem is actually a traversal process of a decision tree.** Now you only need to think about 3 terms: 1. **Path**: the selection that have been made. @@ -29,7 +29,7 @@ def backtrack(Path, Seletion List ): deselect ``` -**The core is the recursion in the for loop. It `makes a selection` before the recursive call and `undoes the selection` after the recursive call **, which is especially simple. +**The core is the recursion in the for loop. It `makes a selection` before the recursive call and `undoes the selection` after the recursive call**, which is especially simple. Then what `makes a selection` and `undo the selection` means? and what is the underlying principle of this framework? Let's use `Permutation` to solve your questions and explore the underlying principle in detail. @@ -51,7 +51,7 @@ In fact, this is the ''backtracking''. You can use it even without a teacher! Th ![](../pictures/backtracking/1en.jpg) -Just traverse this tree from the root to the leaves and record the numbers on the paths, and you will get all the permutations. **We might as well call this tree a “decision tree” for backtracking **for you're actually making decisions on each node. For instance, if you are now at the red node, you will making a decision between the "1" branch and "3" branch. Why only 1 and 3? Because the "2" branch is behind you, you have made this selection before, and the full permutation is not allowed to reuse numbers. +Just traverse this tree from the root to the leaves and record the numbers on the paths, and you will get all the permutations. **We might as well call this tree a “decision tree” for backtracking** for you're actually making decisions on each node. For instance, if you are now at the red node, you will making a decision between the "1" branch and "3" branch. Why only 1 and 3? Because the "2" branch is behind you, you have made this selection before, and the full permutation is not allowed to reuse numbers. **Now you can understand the terms mentioned before more specifically: `[2]` is the “Path”, which records the selections you have made; `[1,3]` is the “Selection List”, which means the current selections you can make; `End Condition` is to traverse to the bottom of the decision tree(here is when the Selection List is empty)**. @@ -59,7 +59,7 @@ If you understand these terms, **you can use the "Path" and "Selection List" as ![](../pictures/backtracking/3en.png) -**The function ```backtrack()``` we defined is actually like a pointer. It is necessary to walk on the tree and maintain the attributes of each node correctly. Whenever it reaches the bottom of the tree, its “Path” is a full permutation **. +**The function ```backtrack()``` we defined is actually like a pointer. It is necessary to walk on the tree and maintain the attributes of each node correctly. Whenever it reaches the bottom of the tree, its “Path” is a full permutation**. Furthermore, how to traverse a tree? it should not be difficult. Recall from the previous article *Framework Thinking of Learning Data Structures*, various search problems are actually tree traversal problems, and the multi-tree traversal framework is: @@ -95,7 +95,7 @@ for seletion in Seletion List: Add the seletion to the Seletion List ``` -**As long as we make a selection before recursion and undo the previous selection after recursion **, we can get the Selection List and Path of each node correctly. +**As long as we make a selection before recursion and undo the previous selection after recursion**, we can get the Selection List and Path of each node correctly. Here shows the code for the full permutation: @@ -140,7 +140,7 @@ We made a few changes here: instead of explicitly recording the "selection List" So far, we have explained the underlying principle of the backtracking through the full permutation problem. Of course, this algorithm is not very efficient, and using the `contains` method for linked list requires $$O(N)$$ time complexity. There are better ways to achieve the purpose by exchanging elements which are more difficult to understand. I won't discuss them in this article. If you are interested, you can google related knowledge by yourself. -However, it must be noted that no matter how optimized, it conforms to the backtracking framework, and the time complexity cannot be lower than $$O (N!)$$.Because exhaustion of the entire decision tree is unavoidable. **This is also a feature of backtracking. Unlike dynamic programming having overlapping subproblems which can be optimized, backtracking is purely violent exhaustion, and time complexity is generally high **. +However, it must be noted that no matter how optimized, it conforms to the backtracking framework, and the time complexity cannot be lower than $$O (N!)$$.Because exhaustion of the entire decision tree is unavoidable. **This is also a feature of backtracking. Unlike dynamic programming having overlapping subproblems which can be optimized, backtracking is purely violent exhaustion, and time complexity is generally high**. After understanding the full permutation problem, you can directly use the backtracking framework to solve some problems. Let's take a brief look at the `N Queen`problem. @@ -266,12 +266,12 @@ def backtrack(...): deselect ``` -**When writing the `backtrack()` function, you need to maintain the “Path” you have traveled and the "selection List” you currently have. When the “End Condition” is triggered, record the “Path” in the result set **. +**When writing the `backtrack()` function, you need to maintain the “Path” you have traveled and the "selection List” you currently have. When the “End Condition” is triggered, record the “Path” in the result set**. Think carefully, is the backtracking and dynamic programming somehow similar? We have repeatedly emphasized in the series of articles about dynamic planning that the three points that need to be clear in dynamic programming are "State", "selection" and "Base Case". Do they correspond to the "Path" that has passed, and the current "selection List" And "End Condition "? To some extent, the brute-force solution phase of dynamic programming is a backtracking. When some problems have overlapping sub-problems, you can use dp table or memo to greatly prune the recursive tree, which becomes dynamic programming. However, today's two problems do not have overlapping subproblems, that is, the problem of backtracking, and the high complexity is inevitable. -**Committed to making the algorithm clear! Welcome to follow me on WeChat public account `labuladong` for more easy-to-understand articles **: +**Committed to making the algorithm clear! Welcome to follow me on WeChat public account `labuladong` for more easy-to-understand articles**: ![labuladong](../pictures/labuladong.png) \ No newline at end of file