Recursive function खुद को problem के छोटे version के साथ call करता है जब तक base case न आ जाए जो chain रोक दे।
हर recursion को दो चीज़ें चाहिए:
def factorial(n):
if n <= 1: # base case
return 1
return n * factorial(n - 1) # recursive case
हर recursive call call stack पर एक frame push करती है। Base case return होने पर frames reverse order में pop होते हैं।
factorial(4)
→ factorial(3)
→ factorial(2)
→ factorial(1) → returns 1
← returns 2
← returns 6
← returns 24
Base case न हो तो stack overflow। Python की default recursion limit 1,000 frames है।
Naïve recursive Fibonacci O(2ⁿ) है क्योंकि same sub-problems बार-बार compute होते हैं। Memoisation इसे O(n) time और space में fix करता है।
from functools import lru_cache
@lru_cache(maxsize=None)
def fib(n):
if n < 2:
return n
return fib(n - 1) + fib(n - 2)
Backtracking recursion है एक twist के साथ: choice बनाओ, recurse करो, फिर choice undo करो और next option try करो। सोचो जैसे maze explore कर रहे हो - आगे जाओ, dead end मिला, वापस आओ, दूसरा रास्ता try करो।
def backtrack(state, choices):
if is_solution(state):
result.append(state.copy())
return
for choice in choices:
if is_valid(choice):
state.add(choice) # choose
backtrack(state, ...) # explore
state.remove(choice) # un-choose
यह choose, explore, un-choose pattern लगभग हर backtracking problem की रीढ़ है।
Backtracking template में recursive call के बाद choice undo क्यों करते हैं?
Sign in to join the discussion
[1, 2, 3] के सभी orderings generate करो। हर level पर unused number choose करो, recurse करो, फिर un-pick करो।
[]
/ | \
[1] [2] [3]
/ \ ...
[1,2] [1,3]
| |
[1,2,3] [1,3,2] ... (6 total)
n! permutations होते हैं, तो time complexity O(n × n!) है।
Combinations (n choose k): हर element पर include करो या skip करो, लेकिन duplicates से बचने के लिए सिर्फ forward recurse करो।
Subsets: same idea बिना size constraint - recursion tree का हर node valid subset है। 2ⁿ subsets होते हैं।
N×N board पर N queens रखो जो एक-दूसरे को attack न करें। N=4 के लिए:
. Q . .
. . . Q
Q . . .
. . Q .
Strategy: हर row में एक queen रखो। हर row के लिए हर column try करो। Column, main diagonal, और anti-diagonal conflicts check करो। Safe हो तो रखो और next row पर recurse करो। Stuck हो तो backtrack।
Conflicts track करो तीन sets से: cols, diag (row − col), anti_diag (row + col)।
N-Queens में diagonal conflicts efficiently कैसे check करते हैं?
Empty cell ढूँढो, digits 1–9 try करो। हर digit के लिए row, column, और 3×3 box constraints check करो। Valid हो तो place करो और recurse करो। कोई digit काम न करे तो undo करो और backtrack। Constraints की pruning huge search space को manageable बनाती है।
2D board of letters और target word दिया है। हर cell से शुरू करो और DFS से four directions में एक character match करते जाओ। Recursion में cells visited mark करो और backtrack पर unmark करो।
Cost branching factor (हर step पर choices) और depth (solution तक steps) पर depend करती है। b branches, d depth: O(bᵈ)।
| Problem | Branching | Depth | Complexity | |---------|-----------|-------|------------| | Permutations | n, n−1, … | n | O(n!) | | Subsets | 2 | n | O(2ⁿ) | | N-Queens | ~n | n | O(n!) worst case |
Pruning का मतलब ऐसी branches skip करना जो fail होंगी:
अच्छी pruning impractical search को fast बना सकती है।
Backtracking algorithm में pruning क्या करती है?