[leetcode] [Tag Backtracking回溯]

2019-01-17  本文已影响0人  jl先生

回溯法

回溯算法实际上一个类似枚举的搜索尝试过程,主要是在搜索尝试过程中寻找问题的解,当发现已不满足求解条件时,就“回溯”返回,尝试别的路径。
解题一般步骤:
(1)针对所给问题,确定问题的解空间:首先应明确定义问题的解空间,问题的解空间应至少包含问题的一个(最优)解。
(2)确定结点的扩展搜索规则
(3)以深度优先方式搜索解空间,并在搜索过程中用剪枝函数避免无效搜索。

17. Letter Combinations of a Phone Number(Medium)

Given a string containing digits from 2-9 inclusive, return all possible letter combinations that the number could represent.
A mapping of digit to letters (just like on the telephone buttons) is given below. Note that 1 does not map to any letters.
Example:
给定一串2-9的数字,返回其在手机按钮上可能的组合。
Input: "23"
Output: ["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"].


image.png

思路:经典的回溯组合问题,可以先把数字对应的字母序列做一个mapping字典,循环或递归加入每个字符,需要一个list保存当前正在加入的字符串。

循环的方法
    def letterCombinations(self, digits):
        """
        :type digits: str
        :rtype: List[str]
        """
        if not digits:
            return []
        mapping = {
            '2':'abc',
            '3':'def',
            '4':'ghi',
            '5':'jkl',
            '6':'mno',
            '7':'pqrs',
            '8':'tuv',
            '9':'wxyz'
        }
        result = [""]
        for d in digits:
            tmp = []
            for letter in mapping[d]:
                for res in result:
                    tmp.append(res + letter)
            result = tmp
        return result
递归的方法
    def letterCombinations(self, digits):
        """
        :type digits: str
        :rtype: List[str]
        """
        if not digits:
            return []
        d = {'2':"abc",
             '3':"def",
             '4':"ghi",
             '5':"jkl",
             '6':"mno",
             '7':"pqrs",
             '8':"tuv",
             '9':"wxyz"
            }
        res = []
        self.dfs(d, digits, "", res)
        return res
    
    def dfs(self, d, digits, tmp , res):
        if not digits:
            res.append(tmp)
        else:
            for num in d[digits[0]]:
                self.dfs(d, digits[1:], tmp + num, res)

22. Generate Parentheses(Medium)

Given n pairs of parentheses, write a function to generate all combinations of well-formed parentheses.
给的那个n对括号,写出所有配对括号的组合
For example, given n = 3, a solution set is:
[
"((()))",
"(()())",
"(())()",
"()(())",
"()()()"
]

思路:dfs回溯,设left,right来表示剩余括号数,每当出现一个括号就让left或right减一。

    def generateParenthesis(self, n):
        """
        :type n: int
        :rtype: List[str]
        """
        if n < 1:
            return [""]
        res = []
        self.dfs(n ,n , res, "")
        return res
        
    def dfs(self, left, right, res, tmp):
        if left > right or left < 0 or right < 0:
            return 
        if left == 0 and right == 0:
            res.append(tmp)
        self.dfs(left - 1, right, res, tmp + '(')
        self.dfs(left , right - 1, res, tmp + ')')

39. Combination Sum(Medium)

Given a set of candidate numbers (candidates) (without duplicates) and a target number (target), find all unique combinations in candidates where the candidate numbers sums to target.
The same repeated number may be chosen from candidates unlimited number of times.
给定一些被选中的数字(没有重复的)和一个目标数,找到满足在给定数字序列中和为目标数的集合。数字可以重复使用
Note:
All numbers (including target) will be positive integers.
The solution set must not contain duplicate combinations.
所有的数都是正整数,不能包含重复的组合。
Example 1:
Input: candidates = [2,3,6,7], target = 7,
A solution set is:
[
[7],
[2,2,3]
]
Example 2:
Input: candidates = [2,3,5], target = 8,
A solution set is:
[
[2,2,2,2],
[2,3,3],
[3,5]
]

思路:该题数组没有排好序,首先得排序。剩下的同样,dfs递归的套路都差不多,用一个辅助函数,每遍历一个数就加入待定的数组tmp,再把目标书target 减去当前遍历过的数。

    def combinationSum(self, candidates, target):
        """
        :type candidates: List[int]
        :type target: int
        :rtype: List[List[int]]
        """
        res = []
        candidates.sort()
        self.dfs(candidates, 0, target, res, [])
        return res
    
    def dfs(self, candidates, index, target, res, tmp):
        if target < 0:
            return 
        if target == 0:
            res.append(tmp)
            return 
        for i in range(index, len(candidates)):
            self.dfs(candidates, i, target - candidates[i] , res, tmp+[candidates[i]])

40. Combination Sum II(Medium)

Given a collection of candidate numbers (candidates) and a target number (target), find all unique combinations in candidates where the candidate numbers sums to target.
Each number in candidates may only be used once in the combination.
给定一些被选中的数字和一个目标数,找到满足在给定数字序列中和为目标数的集合。每个数只能使用一次
Example 1:
Input: candidates = [10,1,2,7,6,1,5], target = 8,
A solution set is:
[
[1, 7],
[1, 2, 5],
[2, 6],
[1, 1, 6]
]

思路:跟39题非常像,区别在于数组内的数不能重复使用,但数组内可以有重复的数,注意一下相同的数不要遍历两次产生重合的结果就好了

    def combinationSum2(self, candidates, target):
        """
        :type candidates: List[int]
        :type target: int
        :rtype: List[List[int]]
        """
        if not candidates:
            return []
        candidates.sort()
        res = []
        self.dfs(candidates, target, res, [])
        return res
    
    def dfs(self, candidates, target, res ,tmp):
        if target < 0:
            return 
        if target == 0:
            res.append(tmp)
            return 
        for i in range(len(candidates)):
            if i!=0 and candidates[i] == candidates[i-1]:
                continue
            self.dfs(candidates[i+1:], target-candidates[i], res, tmp+[candidates[i]])
        

46. Permutations(Medium)

Given a collection of distinct integers, return all possible permutations.
给定不同的整数的集合,返回所有可能的排列。
Input: [1,2,3]
Output:
[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]

思路:O(n2)的方法,如果上面的题会了这道题就算简单题了,47题、77题、78题都是类似的。

    def permute(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        res = []
        self.dfs(nums, res,[])
        return res 
    
    def dfs(self, nums, res,tmp):
        if not nums:
            res.append(tmp)
        else:
            for i in range(len(nums)):
                self.dfs(nums[:i]+nums[i+1:],res,tmp+[nums[i]])

79. Word Search(Medium)

Given a 2D board and a word, find if the word exists in the grid.
给定一个2维数组和一个单词,找到单词是否存在于2维数组中。
board =
[
['A','B','C','E'],
['S','F','C','S'],
['A','D','E','E']
]
Given word = "ABCCED", return true.
Given word = "SEE", return true.
Given word = "ABCB", return false

思路:每次遍历到错误的节点需要返回,最完美的解决办法就是回溯了,从每个节点出发判断上下左右四个节点是不是匹配word的下一个字母,如果匹配则继续dfs递归,不匹配或者超过边界则返回。

    def exist(self, board, word):
        """
        :type board: List[List[str]]
        :type word: str
        :rtype: bool
        """
        if not word: return True
        if not board: return False
        for i in range(len(board)):
            for j in range(len(board[0])):
                if self.dfs(board, i, j, word):
                    return True
        return False
    
    def dfs(self, board, i, j, word):
        if not word:
            return True
        if i >= len(board) or i < 0 or j >= len(board[0]) or j < 0 or board[i][j] != word[0]: #匹配失败跳出递归
            return False
        tmp = board[i][j]
        board[i][j] = '.'
        if self.dfs(board, i+1, j, word[1:]) or self.dfs(board, i-1, j, word[1:]) or \
        self.dfs(board, i, j+1, word[1:]) or self.dfs(board, i, j-1, word[1:]):
            return True
        board[i][j] = tmp
        return False

上一篇下一篇

猜你喜欢

热点阅读