Skip to content

Backtracking Algorithm

The template for backtracking is as follows:

result = []
def backtrack(path, choice_list):
    if end_condition_met:
        result.add(path)
        return

    for choice in choice_list:
        # make a choice
        backtrack(path, choice_list)
        # !!! undo

Permutations (Leetcode 46)

class Solution:
    def permute(self, nums: List[int]) -> List[List[int]]:

        self.results = []
        tracks = []
        used = [False] * len(nums)
        self.backtrack(nums, tracks, used)

        return self.results



    def backtrack(self, nums, tracks, used):

        if len(tracks) == len(nums):
            self.results.append(tracks.copy())
            return 

        for i in range(len(nums)):
            if used[i]:
                continue

            tracks.append(nums[i])
            used[i] = True
            self.backtrack(nums, tracks, used)

            tracks.pop()
            used[i] = False

Subsets (Leetcode 78)

class Solution:
    def subsets(self, nums: List[int]) -> List[List[int]]:

        self.res = []
        tracks = []
        start = 0

        self.backtrack(nums, tracks, start)

        return self.res

    def backtrack(self, nums, tracks, start):

        self.res.append(tracks.copy())

        for i in range(start, len(nums)):
            tracks.append(nums[i])
            self.backtrack(nums, tracks, i+1)
            tracks.pop()

Combinations (Leetcode 77)

class Solution:
    def combine(self, n: int, k: int) -> List[List[int]]:
        self.res = []
        tracks = []
        start = 0

        nums = range(1, n+1)

        self.backtrack(nums, tracks, start, k)

        return self.res

    def backtrack(self, nums, tracks, start, k):

        if len(tracks) == k:
            self.res.append(tracks.copy())
            return

        for i in range(start, len(nums)):
            tracks.append(nums[i])
            self.backtrack(nums, tracks, i+1, k)
            tracks.pop()

Subsets II (Leetcode 90)

class Solution:
    def subsetsWithDup(self, nums: List[int]) -> List[List[int]]:

        self.res = []
        tracks = []
        start = 0

        nums.sort()

        self.backtrack(nums, tracks, start)

        return self.res

    def backtrack(self, nums, tracks, start):

        self.res.append(tracks.copy())

        for i in range(start, len(nums)):
            if i > start and nums[i] == nums[i-1]:
                continue

            tracks.append(nums[i])
            self.backtrack(nums, tracks, i+1)
            tracks.pop()

Combination Sum II (Leetcode 40)

class Solution:
    def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
        self.res = []
        tracks = []

        candidates.sort()

        self.backtrack(candidates, tracks, target, 0)

        return self.res


    def backtrack(self, candidates, tracks, target, start):
        if target == 0:
            self.res.append(tracks.copy())
            return

        for i in range(start, len(candidates)):
            if candidates[i] > target:
                continue

            if i > start and candidates[i] == candidates[i-1]:
                continue

            tracks.append(candidates[i])

            self.backtrack(candidates, tracks, target - candidates[i], i+1)
            tracks.pop()

Permutations II (Leetcode 47)

class Solution:
    def permuteUnique(self, nums: List[int]) -> List[List[int]]:

        self.res = []
        tracks = []
        used = [False] * len(nums)
        nums.sort()

        self.backtrack(nums, tracks, used)

        return self.res


    def backtrack(self, nums, tracks, used):

        if len(nums) == len(tracks):
            self.res.append(tracks.copy())

        for i in range(len(nums)):
            if i>0 and nums[i-1] == nums[i] and (not used[i-1]):
                continue
            if used[i]:
                continue
            tracks.append(nums[i])
            used[i] = True

            self.backtrack(nums, tracks, used)
            tracks.pop()
            used[i] = False

Combination Sum (Leetcode 39)

class Solution:
    def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:

        self.res = []
        tracks = []
        self.backtrack(candidates, tracks, target, 0)

        return self.res


    def backtrack(self, candidates, tracks, target, start):

        if target == 0:
            self.res.append(tracks.copy())

        for i in range(start, len(candidates)):
            if candidates[i] > target:
                continue

            tracks.append(candidates[i])
            self.backtrack(candidates, tracks, target - candidates[i], i)
            tracks.pop()