0% found this document useful (0 votes)
67 views27 pages

Backtracking PDF

Backtracking is an algorithmic technique used in Python for solving problems incrementally by exploring all possibilities and reverting if a solution fails. It is particularly effective for constraint satisfaction, combinatorial, and search problems, such as Sudoku and the N-Queens problem. The method involves a depth-first search approach, where solutions are built step by step, and paths that do not meet constraints are eliminated to improve efficiency.

Uploaded by

bhavitmathangi
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
67 views27 pages

Backtracking PDF

Backtracking is an algorithmic technique used in Python for solving problems incrementally by exploring all possibilities and reverting if a solution fails. It is particularly effective for constraint satisfaction, combinatorial, and search problems, such as Sudoku and the N-Queens problem. The method involves a depth-first search approach, where solutions are built step by step, and paths that do not meet constraints are eliminated to improve efficiency.

Uploaded by

bhavitmathangi
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 27

Back tracking :

What Is Backtracking in Python?


Backtracking is a general algorithmic technique for solving problems
incrementally, one piece at a time. Whenever we find that the current path or
partial solution doesn’t satisfy the constraints of the problem, we backtrack (undo
the last step) and try another path. In Python, it often involves the following:

Constraint Satisfaction Problems: Such as Sudoku or the N-Queens problem.

Combinatorial Problems: Generating combinations, permutations, subsets,


etc.

Search Problems: Exploring potential candidate solutions (e.g., maze-solving).

How is Backtracking Different from Recursion?


backtrakign + controlled recursion ans in place changes (pass by refrence )

Feature Recursion Backtracking

A technique where a function A type of recursion where we explore


Definition calls itself to solve all possibilities and revert if a solution is
subproblems. not found.

Solves smaller subproblems Tries all possible solutions and


Working
and combines results. backtracks if a constraint is violated.

Problems like Fibonacci, Constraint satisfaction problems like N-


Used In
Factorial, Tree Traversal. Queens, Sudoku, Graph Coloring.

May not eliminate unnecessary Prunes branches that do not lead to


Optimization
paths. solutions, improving efficiency.

When to Use Backtracking?


Use backtracking when:

1. The problem has multiple solutions, and we need to explore all possibilities.

2. We need to construct a solution step by step.

Back tracking : 1
3. We can eliminate paths that do not satisfy constraints early.

4. The problem has a combinatorial nature (like permutations, combinations,


and puzzles).

Concept of Backtracking
Backtracking follows a Depth-First Search (DFS) approach. It works as:

1. Pick a starting point.

2. Try different options recursively.

3. If a solution satisfies constraints, proceed further.

4. If a solution fails, backtrack (undo the last step) and try another path.

5. Repeat until a valid solution is found or all possibilities are exhausted.

Example :
1. Solving Sudoku (Puzzle Solving)
Problem: Fill a 9×9 grid with numbers 1-9 so that no number repeats in any
row, column, or 3×3 subgrid.

Backtracking Role: Tries placing a number in a cell, checks constraints, and


backtracks if conflicts arise.

👉 Example:
If placing 5 in a cell leads to an invalid Sudoku, we remove it and try another
number.

2. N-Queens Problem (Chess Strategy)


Problem: Place N queens on an N×N chessboard so that no two queens
attack each other.

Backtracking Role: Places a queen, checks for conflicts, and backtracks if


necessary.

Back tracking : 2
👉 Example:
If a queen placed in row 3 conflicts with another, we backtrack and try another
column.

3. Word Search (Puzzle Games)


Problem: Find a word in a grid by moving up, down, left, right, or diagonally.

Backtracking Role: Starts from each letter, tries forming the word, and
backtracks if a letter sequence fails.

👉 Example:
If searching for "CAT" in a grid, we start at C, try A, and if T is missing, we
backtrack.

4. Maze Solving (Pathfinding)


Problem: Find a path from the start to the exit in a maze.

Backtracking Role: Moves in a direction, backtracks if it hits a dead-end, and


tries another path.

👉 Example:
If moving right leads to a dead end, backtrack and try down instead.

5. Generating Combinations (Password Cracking, Scheduling)


Problem: Find all valid combinations of elements (e.g., scheduling tasks,
generating secure passwords).

Backtracking Role: Selects an option, tests constraints, and backtracks if it's


invalid.

👉 Example:
A system generating 6-character passwords tries different letters but backtracks
when a rule is violated.

6. AI and Game Development (Decision Making)

Back tracking : 3
Problem: AI chooses the best move in a game (e.g., Chess, Tic-Tac-Toe).

Backtracking Role: Simulates possible moves, backtracks on bad decisions,


and finds the optimal move.

👉 Example:
In Chess, if moving a bishop results in losing a queen, AI backtracks and selects a
better move.

7. Robot Path Planning (Self-Driving Cars)


Problem: Find the best path from one point to another while avoiding
obstacles.

Backtracking Role: Explores paths, backtracks when obstacles block a route,


and finds an optimal path.

Subset Sum Problem (Backtracking Approach)

Problem Statement:
Given an array of integers, find all subsets whose sum equals a given target.

Python Implementation

python
CopyEdit
def subset_sum(arr, target, index=0, subset=[]):
if sum(subset) == target:
print(subset) # Print valid subset
return
if index >= len(arr):
return

# Include current element


subset_sum(arr, target, index + 1, subset + [arr[index]])

Back tracking : 4
# Exclude current element (backtrack)
subset_sum(arr, target, index + 1, subset)

# Example usage
arr = [2, 3, 5, 7]
target = 7
subset_sum(arr, target)

Output:

csharp
CopyEdit
[2, 5]
[7]

Backtracking Tree (Step Visualization)


We start with an empty subset [] and explore all possibilities.

css
CopyEdit
[]
/ \
[2] []
/ \ / \
[2,3] [2] [3] []
/ \ / \ / \ / \
[2,3,5] [2,3] [2,5] [2] [3,5] [3] [5] []
/ \ / \ / \ / \ / \ / \ / \ / \
[2,3,5,7] X [2,5,7] X [2,7] X [3,7] X [5,7] X [7] X

Back tracking : 5
X denotes a path where the sum does not match the target.

Valid subsets: [2, 5] , [7] .

Time Complexity Analysis


The time complexity of this approach is O(2^n), where n is the number of
elements in arr .

Each element has two choices: include or exclude, leading to 2^n recursive
calls.

In the worst case, we explore all subsets before finding the valid ones.

Step-by-Step Execution Trace


Let's break down the recursive calls for arr = [2, 3, 5, 7] and target = 7 .

Step Subset Sum Decision

Start [] 0 Explore 2 and exclude 2

Include 2 [2] 2 Explore 3 and exclude 3

Include 3 [2,3] 5 Explore 5 and exclude 5

Include 5 [2,3,5] 10 Exceeds target → Backtrack

Exclude 5 [2,3] 5 Explore 7

Include 7 [2,3,7] 12 Exceeds target → Backtrack

Exclude 3 [2] 2 Explore 5

Include 5 [2,5] 7 Valid subset → Print

Backtrack [2] 2 Explore 7

Include 7 [2,7] 9 Exceeds target → Backtrack

Exclude 2 [] 0 Explore 3

Include 3 [3] 3 Explore 5

Include 5 [3,5] 8 Exceeds target → Backtrack

Exclude 5 [3] 3 Explore 7

Include 7 [3,7] 10 Exceeds target → Backtrack

Back tracking : 6
Exclude 3 [] 0 Explore 5

Include 5 [5] 5 Explore 7

Include 7 [5,7] 12 Exceeds target → Backtrack

Exclude 5 [] 0 Explore 7

Include 7 [7] 7 Valid subset → Print

Key Takeaways
1. Backtracking explores all subsets recursively.

2. Time Complexity: O(2n) due to the exponential number of subset choices.

O(2n)O(2^n)

3. Backtracking tree visualization helps understand recursive calls.

4. Subset pruning (stopping early when exceeding target) can improve


efficiency.

Recursive Tree Exploration

Step 1: Include arr[0] = 2

python
CopyEdit
subset_sum([2, 3, 5, 7], 7, index=1, subset=[2])

Moves to index=1 (next element).

Step 2: Include arr[1] = 3

python
CopyEdit

Back tracking : 7
subset_sum([2, 3, 5, 7], 7, index=2, subset=[2, 3])

Moves to index=2 .

Step 3: Include arr[2] = 5

python
CopyEdit
subset_sum([2, 3, 5, 7], 7, index=3, subset=[2, 3, 5])

sum([2, 3, 5]) = 10 (exceeds target=7 ), so this branch stops.

Step 4: Backtrack (Exclude 5 & Try 7 )

python
CopyEdit
subset_sum([2, 3, 5, 7], 7, index=3, subset=[2, 3])

Try including 7 next.

python
CopyEdit
subset_sum([2, 3, 5, 7], 7, index=4, subset=[2, 3, 7])

sum([2, 3, 7]) = 12 (exceeds 7 ), so this branch stops.

Step 5: Backtrack to Try 2 and 5 Combination

python
CopyEdit

Back tracking : 8
subset_sum([2, 3, 5, 7], 7, index=3, subset=[2, 5])

sum([2, 5]) = 7 → ✅ Valid subset → print([2, 5]) .

Step 6: Backtrack to Try 3 and 5

python
CopyEdit
subset_sum([2, 3, 5, 7], 7, index=2, subset=[3])

Include 5 : sum([3, 5]) = 8 (exceeds 7 ), so discard this path.

Step 7: Try Single 7

python
CopyEdit
subset_sum([2, 3, 5, 7], 7, index=3, subset=[7])

sum([7]) = 7 → ✅ Valid subset → print([7]) .

Final Output

csharp
CopyEdit
[2, 5]
[7]

Key Takeaways
✅ Backtracking explores both inclusion and exclusion of elements.

Back tracking : 9
✅ Uses recursion to generate all possible subsets.
✅ Stops early when the sum exceeds the target.
✅ Ensures all valid subsets are found without duplicate calculations.

2, . Understanding Backtracking for


Generating Permutations in Python
🔹 Problem Explanation
We need to generate all possible permutations of a given list of numbers using
backtracking.

🔹 What is Backtracking?
Backtracking is an algorithmic technique where we:

1. Try a possible solution (make a choice).

2. Recursively explore further.

3. Undo the choice (backtrack) if it doesn't lead to a valid solution.

🔹 Understanding the Given Code


python
CopyEdit
def permute(nums, i=0):
if i == len(nums):
print(nums) # Print the current permutation
return

for j in range(i, len(nums)):


# Swap nums[i] and nums[j]

Back tracking : 10
nums[i], nums[j] = nums[j], nums[i]
print(f"Swapped nums[{i}] with nums[{j}]: {nums}") # Debugging statem
ent

# Recursive call for the next index


permute(nums, i + 1)

# Backtrack (swap back to restore original array)


nums[i], nums[j] = nums[j], nums[i]
print(f"Backtracked nums[{i}] with nums[{j}]: {nums}") # Debugging stat
ement

# Example Usage
nums = [1, 2, 3]
print("All Permutations:")
permute(nums)

Backtracking Tree (Step Visualization)


We start with nums = [1, 2, 3] and recursively swap elements to generate
permutations.

less
CopyEdit
[1,2,3]
/ | \
[1,2,3] [2,1,3] [3,2,1]
/ \ / \ / \
[1,2,3] [1,3,2] [2,1,3] [2,3,1] [3,2,1] [3,1,2]

Each level represents choosing a different element to place in the current position.

Back tracking : 11
Time Complexity Analysis
Total permutations of n numbers: n!

n!n!

Each permutation takes O(n)O(n)O(n) swaps

Overall complexity: O(n!×n) (can be optimized to O(n!))

O(n!×n)O(n! \times n)
O(n!)O(n!)

Step-by-Step Execution Trace


Step Current List Swaps Action

Start [1,2,3] - Begin recursion

Swap(1,1) [1,2,3] No change Recur on [2,3]

Swap(2,2) [1,2,3] No change Recur on [3] , print [1,2,3]

Swap Back [1,2,3] - Backtrack

Swap(2,3) [1,3,2] 2 and 3 swapped Recur on [2] , print [1,3,2]

Swap Back [1,2,3] - Backtrack

Swap(1,2) [2,1,3] 1 and 2 swapped Recur on [1,3]

Swap(2,2) [2,1,3] No change Print [2,1,3]

Swap(2,3) [2,3,1] 1 and 3 swapped Print [2,3,1]

Swap Back [1,2,3] - Backtrack

Swap(1,3) [3,2,1] 1 and 3 swapped Recur on [2,1]

Swap(2,2) [3,2,1] No change Print [3,2,1]

Swap(2,3) [3,1,2] 1 and 2 swapped Print [3,1,2]

🔹 Time Complexity Analysis


The function explores all possible orderings of N numbers.

The total number of permutations is N! (factorial of N).

Back tracking : 12
Each permutation requires O(N) swaps and recursive calls.

Total Time Complexity: O(N * N!).

Space Complexity:
O(N) recursive calls (due to function call stack).

O(1) additional space (since we modify nums in-place).

🔹 Summary
✅ Uses backtracking to explore all permutations.
✅ Swaps elements to generate unique orderings.
✅ Backtracks to restore the original state.
✅ Time Complexity: O(N * N!) (efficient for small N).

3 . Detailed Explanation of Including &


Excluding in Subset Generation
(Backtracking)

🔹 Understanding the Core Idea


In this problem, we are generating all subsets (power set) of a given list of
numbers.
To generate subsets, we make a binary choice for each element:
✅ Include it in the subset ✅ Exclude it from the subset
This decision tree explores all possible combinations, and we use recursion +
backtracking to traverse it.

Back tracking : 13
🔹 Given Code
python
CopyEdit
def generate_subsets(nums, index=0, current_subset=[], result=[]):
print(f"Called with index={index}, current_subset={current_subset}") # Deb
ugging print

if index == len(nums):
result.append(current_subset[:]) # Store a copy of the current subset
print(f"Subset completed: {current_subset} -> Added to result\n") # Deb
ugging print
return

# Exclude the current element


print(f"Excluding {nums[index]} at index {index}") # Debugging print
generate_subsets(nums, index + 1, current_subset, result)

# Include the current element


print(f"Including {nums[index]} at index {index}") # Debugging print
current_subset.append(nums[index])
generate_subsets(nums, index + 1, current_subset, result)

# Backtrack (Remove last element before returning)


print(f"Backtracking: Removing {current_subset[-1]} at index {index}") # De
bugging print
current_subset.pop()

return result

# Example Usage
nums = [1, 8, 7]
print("All Unique Subsets:")

Back tracking : 14
print(generate_subsets(nums))

🔹 Step-by-Step Execution (Including & Excluding)


We start with:

plaintext
CopyEdit
nums = [1, 8, 7]

We recursively explore subsets by either including or excluding each element.

🌟 Step 1: Start at index = 0 (Element: 1 )

plaintext
CopyEdit
generate_subsets([1, 8, 7], index=0, current_subset=[])

Two choices:
1️⃣
Exclude → Move to
1 index = 1

2️⃣ Include → Add to


1 1 current_subset and move to index = 1

🌟 Step 2: index = 1 (Element: 8 )

plaintext
CopyEdit
generate_subsets([1, 8, 7], index=1, current_subset=[])

Back tracking : 15
Two choices:
1️⃣
Exclude → Move to
8 index = 2

2️⃣ Include → Add8 8 to current_subset and move to index = 2

🌟 Step 3: index = 2 (Element: 7 )

plaintext
CopyEdit
generate_subsets([1, 8, 7], index=2, current_subset=[])

Two choices:
1️⃣
Exclude → Move to
7 index = 3

2️⃣ Include → Add7 7 to current_subset and move to index = 3

🌟 Step 4: index = 3 (Base Case)

plaintext
CopyEdit
generate_subsets([1, 8, 7], index=3, current_subset=[])

Since index == len(nums) , we store the subset and backtrack.

🔄 Backtracking Process
1. Backtrack from [1, 8, 7] → Remove 7

2. Backtrack from [1, 8] → Remove 8

3. Backtrack from [1] → Remove 1

4. Try all other combinations

🔹
Back tracking : 16
🔹 Full Execution Trace
Below is the full decision tree showing how the function explores all subsets:

plaintext
CopyEdit
Start with: []
├── Exclude 1 → []
│ ├── Exclude 8 → []
│ │ ├── Exclude 7 → []
│ │ │ ├── (Base case: Add []) ✅
│ │ ├── Include 7 → [7]
│ │ │ ├── (Base case: Add [7]) ✅
│ ├── Include 8 → [8]
│ │ ├── Exclude 7 → [8]
│ │ │ ├── (Base case: Add [8]) ✅
│ │ ├── Include 7 → [8,7]
│ │ │ ├── (Base case: Add [8,7]) ✅
├── Include 1 → [1]
│ ├── Exclude 8 → [1]
│ │ ├── Exclude 7 → [1]
│ │ │ ├── (Base case: Add [1]) ✅
│ │ ├── Include 7 → [1,7]
│ │ │ ├── (Base case: Add [1,7]) ✅
│ ├── Include 8 → [1,8]
│ │ ├── Exclude 7 → [1,8]
│ │ │ ├── (Base case: Add [1,8]) ✅
│ │ ├── Include 7 → [1,8,7]
│ │ │ ├── (Base case: Add [1,8,7]) ✅

At each step:

We exclude first, then include.

✅ We store subsets only at index == len(nums) .

Back tracking : 17
✅ Backtracking ensures all possibilities are explored.
🔹 Final Output (All Subsets)
plaintext
CopyEdit
[]
[7]
[8]
[8, 7]
[1]
[1, 7]
[1, 8]
[1, 8, 7]

Each subset is generated without duplicates.

🔹 Time Complexity Analysis


1. Each number has two choices (include/exclude).

2. If there are N numbers, we make 2^N recursive calls.

3. Time Complexity: O(2^N).

Space Complexity:
O(N) for the recursive call stack.

O(2^N) for storing all subsets.

🔹 Summary
✅ Uses backtracking to explore all subsets.
✅ Recursive function with include/exclude choices.
✅ Backtracks to restore original state.
Back tracking : 18
✅ Time Complexity: O(2^N) (Exponential growth).

Combination Problem Statement :

Backtracking Approach
The code will generate all possible combinations:

Python Code

python
CopyEdit
def backtrack(n, k, start, path, result):
if len(path) == k:
result.append(path[:])
return

for i in range(start, n + 1):


path.append(i)
backtrack(n, k, i + 1, path, result)
path.pop()

def combine(n, k):


result = []
backtrack(n, k, 1, [], result)
return result

# Example Usage:
n=4
k=2

Back tracking : 19
print(combine(n, k))

Output

python
CopyEdit
[[1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4]]

Backtracking Tree

scss
CopyEdit
Start with []
├── Add 1 → [1]
│ ├── Add 2 → [1,2] ✅
(Valid)
│ ├── Remove 2 → [1]
│ ├── Add 3 → [1,3] ✅ (Valid)
│ ├── Remove 3 → [1]
│ ├── Add 4 → [1,4] ✅ (Valid)
│ ├── Remove 4 → [1]
│ ├── Remove 1 → []
├── Add 2 → [2]
│ ├── Add 3 → [2,3] ✅
(Valid)
│ ├── Remove 3 → [2]
│ ├── Add 4 → [2,4] ✅ (Valid)
│ ├── Remove 4 → [2]
│ ├── Remove 2 → []
├── Add 3 → [3]
│ ├── Add 4 → [3,4] (Valid) ✅
│ ├── Remove 4 → [3]
│ ├── Remove 3 → []

Back tracking : 20
├── Add 4 → [4] (No more numbers left)

Backtracking Tree for n = 4 and k = 3


We need to generate all combinations of size 3 from the set {1, 2, 3, 4}.

Step-by-Step Recursive Exploration


Start with an empty path []

Pick numbers one by one and ensure combinations have exactly k=3

elements.

Backtrack when we reach the required size, removing the last element and
trying another number.

Recursive Backtracking Tree Structure

Start with []
├── Add 1 → [1]
│ ├── Add 2 → [1,2]
│ │ ├── Add 3 → [1,2,3] ✅
(Valid)
│ │ ├── Remove 3 → [1,2]
│ │ ├── Add 4 → [1,2,4] ✅
(Valid)
│ │ ├── Remove 4 → [1,2]
│ ├── Remove 2 → [1]
│ ├── Add 3 → [1,3]
│ │ ├── Add 4 → [1,3,4] ✅
(Valid)
│ │ ├── Remove 4 → [1,3]
│ ├── Remove 3 → [1]
│ ├── Add 4 → [1,4] (Not enough elements left)
│ ├── Remove 4 → [1]

Back tracking : 21
│ ├── Remove 1 → []
├── Add 2 → [2]
│ ├── Add 3 → [2,3]
│ │ ├── Add 4 → [2,3,4] ✅
(Valid)
│ │ ├── Remove 4 → [2,3]
│ ├── Remove 3 → [2]
│ ├── Add 4 → [2,4] (Not enough elements left)
│ ├── Remove 4 → [2]
│ ├── Remove 2 → []
├── Add 3 → [3]
│ ├── Add 4 → [3,4] (Not enough elements left)
│ ├── Remove 4 → [3]
│ ├── Remove 3 → []
├── Add 4 → [4] (Not enough elements left)

Python Implementation

python
CopyEdit
def combine(n, k, start=1, current=[]):
if len(current) == k:
print(current) # Print valid combination
return

for i in range(start, n + 1):


combine(n, k, i + 1, current + [i]) # Pick element and move forward

# Example usage
print("Combinations for n=4, k=2:")
combine(4, 2)

Back tracking : 22
Output (n = 4, k = 2):

csharp
CopyEdit
[1, 2]
[1, 3]
[1, 4]
[2, 3]
[2, 4]
[3, 4]

Backtracking Tree (Step Visualization for n=4, k=2)


We start with an empty subset and explore possibilities recursively.

less
CopyEdit
[]
/ | | \
[1] [2] [3] [4]
/ \ | |
[1,2] [1,3] [1,4]
| | |
[2,3] [2,4] [3,4]

Each level represents picking the next element while maintaining order.

Time Complexity Analysis

For n = 4, k = 2:

Back tracking : 23
mathematica
CopyEdit
C(4,2) = 4! / (2!(4-2)!) = 6

So, we have 6 recursive calls that generate valid combinations.

Step-by-Step Execution Trace


Step Current List Action

Start [] Begin recursion

Pick 1 [1] Move forward

Pick 2 [1,2] Print [1,2]

Backtrack [1] Undo last step

Pick 3 [1,3] Print [1,3]

Backtrack [1] Undo last step

Pick 4 [1,4] Print [1,4]

Backtrack [] Undo last step

Pick 2 [2] Move forward

Pick 3 [2,3] Print [2,3]

Backtrack [2] Undo last step

Pick 4 [2,4] Print [2,4]

Backtrack [] Undo last step

Pick 3 [3] Move forward

Pick 4 [3,4] Print [3,4]

Case 2: Combinations for n = 4, k = 3


Updating the function call:

Back tracking : 24
python
CopyEdit
print("Combinations for n=4, k=3:")
combine(4, 3)

Output:

csharp
CopyEdit
[1, 2, 3]
[1, 2, 4]
[1, 3, 4]
[2, 3, 4]

Backtracking Tree (n=4, k=3)

less
CopyEdit
[]
/ | | \
[1] [2] [3] [4]
/ \ |
[1,2] [1,3] [1,4]
/ | |
[1,2,3] [1,2,4] [1,3,4]
\ \
[2,3,4]

Time Complexity Analysis for n=4, k=3

Back tracking : 25
mathematica
CopyEdit
C(4,3) = 4! / (3!(4-3)!) = 4

So, 4 recursive calls generate valid combinations.

Step-by-Step Execution Trace

Step Current Combination ( current ) Action

Start [] Begin recursion

Pick 1 [1] Move forward

Pick 2 [1, 2] Move forward

Pick 3 [1, 2, 3] Valid combination → Print [1, 2, 3]

Backtrack [1, 2] Undo last step

Pick 4 [1, 2, 4] Valid combination → Print [1, 2, 4]

Backtrack [1, 2] Undo last step

Backtrack [1] Undo last step

Pick 3 [1, 3] Move forward

Pick 4 [1, 3, 4] Valid combination → Print [1, 3, 4]

Backtrack [1, 3] Undo last step

Backtrack [1] Undo last step

Pick 4 [1, 4] Not enough elements left → Backtrack

Backtrack [] Undo last step

Pick 2 [2] Move forward

Pick 3 [2, 3] Move forward

Pick 4 [2, 3, 4] Valid combination → Print [2, 3, 4]

Backtrack [2, 3] Undo last step

Backtrack [2] Undo last step

Pick 4 [2, 4] Not enough elements left → Backtrack

Back tracking : 26
Backtrack [] Undo last step

Pick 3 [3] Not enough elements left → Backtrack

Pick 4 [4] Not enough elements left → Backtrack

Back tracking : 27

You might also like