LeetCode DFS & Backtracking系列: 17, 46, 47, 77, 78, 90, 286, 76, 93题解系列1:(17,46,47) (python)

LeetCode 17, 46, 47, 77, 78, 90, 286, 79, 93: DFS & Backtracking方法题解 (python)

描述:

DFS 是一种非常重要的算法思想,也有很多具体的应用。这里简单总结一下LeetCode中比较基础,比较典型的DFS / Backtracking法的应用。在这里试图总结出一个“通用”的模版,以及一些题需要的注意的点。

链接: 17. Letter Combinations of a Phone Number.
链接: 46. Permutations.
链接: 47. Permutations II.
链接: 77. Combinations.
链接: 78. Subsets.
链接: 90. Subsets II.
链接: 286. Walls and Gates.
链接: 79. Word Search.
链接: 93. Restore IP Addresses.

系列1: 174647

17. Letter Combinations of a Phone Number.
思路:

这是典型的排列问题。一看到排列问题,就能想到backtracking/dfs法去做,这道题就可解。

class Solution:
    def letterCombinations(self, digits: str) -> List[str]:
        phone = {'2': ['a', 'b', 'c'],  把电话按键对应的字典表示出来
                 '3': ['d', 'e', 'f'],
                 '4': ['g', 'h', 'i'],
                 '5': ['j', 'k', 'l'],
                 '6': ['m', 'n', 'o'],
                 '7': ['p', 'q', 'r', 's'],
                 '8': ['t', 'u', 'v'],
                 '9': ['w', 'x', 'y', 'z']}
        self.result = []
        if not digits:
            return self.result
        self.dfs(digits, phone, 0, '')
        return self.result
    def dfs(self, digits, phone, start, res): 
        if len(res) == len(digits):   
            self.result.append(res)
            return    注意,这里要用return退出函数
        for i in phone[digits[start]]:
            self.dfs(digits, phone, start+1, res+i)   函数的目的和递归一句话就够了。
总结:

注意函数退出条件,注意dfs的退出。其他地方都是套路。

46. Permutations
思路:

典型的全排列问题。回溯法/dfs去解即可。
DFS 解法1:

class Solution:
    def permute(self, nums: List[int]) -> List[List[int]]:
        self.result = []
        self.dfs(nums, [])
        return self.result
    def dfs(self, nums, res):
        if len(res) == len(nums):
            self.result.append(res)
        for i in range(len(nums)):
            if nums[i] not in res:
                self.dfs(nums, res+[nums[i]])

DFS 解法2:

class Solution:
    def permute(self, nums: List[int]) -> List[List[int]]:
        self.result = []
        self.dfs(nums, [])
        return self.result
    def dfs(self, nums, res):
        if not nums:
            self.result.append(res)
        for i in range(len(nums)):
            self.dfs(nums[:i]+nums[i+1:], res+[nums[i]])
总结:

解法1是比较常规的一种思路:dfs函数的退出标志是子结果(res)的长度和nums长度相同。这很好理解。
解法2相对则稍微有那么一点不同。退出的条件是输入的数组为空时退出:因为我们在递归的时候,不断的在把i往后遍历,同时输入数组的时候会把nums[i]剔除,nums[i]会加入到res中。这样,当输入为空数组的时候,就说明每个nums[i]都被考虑了一次了,自然就可以退出函数。
这里的dfs处理和其他题目略有区别。
个人认为第一种传统一些的解法更适于这类题型的整体总结与掌握。

链接: 47. Permutations II.
思路:

这是本类题目中第一次出现需要重复值处理的情况。对于重复值,一般需要注意两点:
1)原数组排序
2)标记处理过的值
一定不能忘记排序!

class Solution:
    def permuteUnique(self, nums: List[int]) -> List[List[int]]:
        self.result = []
        visited = [False]* len(nums) 
        self.dfs(sorted(nums), [], visited)  一定不能忘记排序!
        
        return self.result
    def dfs(self, nums, res, seen):  需要一个seen变量,去标记已经访问过的值
        if len(nums) == len(res):
            self.result.append(res)
        for i in range(len(nums)):
            if not seen[i]:
                if nums[i-1] == nums[i] and not seen[i-1] and i>0:  重复值处理的“话术”
                    continue
                seen[i] = True      nums[i]已经访问了:人人为我
                self.dfs(nums, res+[nums[i]], seen)
                seen[i] = False		别忘了为下一次递归还原:我为人人
总结:

需要重复值处理的时候,记住两点即可:
1)排序
2)“人人为我,我为人人”

总结:

1)看到排列问题就想到 DFS/Backtracking
2)重复值处理的两个关键点

参考链接:
链接: General Python Solution of Backtracking Questions.
链接: Recision II.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值