leetcode刷题:递归 / 回溯

系列文章目录

leetcode刷题:第一周
leetcode刷题:第二周
leetcode刷题:二分查找
leetcode刷题:双指针
leetcode刷题:广度/深度优先搜索
leetcode刷题:递归 / 回溯



前言

这次博客记录一些leetcode有关递归和回溯的题目


递归/回溯

1.子集

给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。

解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。

示例 1:

输入:nums = [1,2,3]
输出:[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]
示例 2:

输入:nums = [0]
输出:[[],[0]]

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

        def backtrack(start, k, cur, nums):
            if k == 0:
            	#使用[:]调用一块新内存
                result.append(cur[:])
                return
            for i in range(start, n):
                cur.append(nums[i])
                backtrack(i + 1, k - 1, cur, nums)
                cur.pop()

        n = len(nums)
        for k in range(n + 1):
            backtrack(0, k, [], nums)
        return result

2.子集 II

给你一个整数数组 nums ,其中可能包含重复元素,请你返回该数组所有可能的子集(幂集)。

解集 不能 包含重复的子集。返回的解集中,子集可以按 任意顺序 排列。

示例 1:

输入:nums = [1,2,2]
输出:[[],[1],[1,2],[1,2,2],[2],[2,2]]
示例 2:

输入:nums = [0]
输出:[[],[0]]

class Solution:
    def subsetsWithDup(self, nums: List[int]) -> List[List[int]]:
    	#先排序可以避免重复
        nums.sort()
        result = []

        def backtrack(start, k, cur, nums):
            if k == 0:
            	#加入结果列表前,判断结果是否存在
                if cur not in result:
                    result.append(cur[:])
                return
            for i in range(start, n):
                cur.append(nums[i])
                backtrack(i + 1, k - 1, cur, nums)
                cur.pop()

        n = len(nums)
        for k in range(n + 1):
            backtrack(0, k, [], nums)
        return result

3.全排列 II

给定一个可包含重复数字的序列 nums ,按任意顺序 返回所有不重复的全排列。

示例 1:

输入:nums = [1,1,2]
输出:
[[1,1,2],
[1,2,1],
[2,1,1]]
示例 2:

输入:nums = [1,2,3]
输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]

class Solution:
    def permuteUnique(self, nums: List[int]) -> List[List[int]]:
        result = []
        lens = len(nums)
        used = [0] * lens
        if lens == 0:
            return []
        depth = 0
        path = []

        def dfs(nums, lens, depth, used, path):
            if depth == lens and path[:] not in result:
                result.append(path[:])
                return
            for i in range(lens):
                if used[i] == 1:
                    continue
                path.append(nums[i])
                used[i] = 1
                dfs(nums, lens, depth + 1, used, path)
                path.pop()
                used[i] = 0

        dfs(nums, lens, depth, used, path)
        return result

4.组合总和

给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。

candidates 中的 同一个 数字可以 无限制重复被选取 。如果至少一个数字的被选数量不同,则两种组合是不同的。

对于给定的输入,保证和为 target 的不同组合数少于 150 个。

示例 1:

输入:candidates = [2,3,6,7], target = 7
输出:[[2,2,3],[7]]
解释:
2 和 3 可以形成一组候选,2 + 2 + 3 = 7 。注意 2 可以使用多次。
7 也是一个候选, 7 = 7 。
仅有这两种组合。
示例 2:

输入: candidates = [2,3,5], target = 8
输出: [[2,2,2,2],[2,3,3],[3,5]]
示例 3:

输入: candidates = [2], target = 1
输出: []

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

        def dfs(candidates, target, idx):
            if idx == len(candidates):
                return

            if target == 0:
                ans.append(combine[:])
                return

            dfs(candidates, target, idx + 1)
            if target - candidates[idx] >= 0:
                combine.append(candidates[idx])
                dfs(candidates, target - candidates[idx], idx)
                combine.pop()

        dfs(candidates, target, 0)
        return ans

5.组合总和 II

给定一个候选人编号的集合 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。

candidates 中的每个数字在每个组合中只能使用 一次 。

注意:解集不能包含重复的组合。

示例 1:

输入: candidates = [10,1,2,7,6,1,5], target = 8,
输出:
[
[1,1,6],
[1,2,5],
[1,7],
[2,6]
]
示例 2:

输入: candidates = [2,5,2,1,2], target = 5,
输出:
[
[1,2,2],
[5]
]

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

        def backtrack(candidates, target, sum, begin):
            if sum == target:
                res.append(path[:])

            for i in range(begin, len(candidates)):
                if i > begin and candidates[i] == candidates[i - 1]:
                    continue
                rs = candidates[i] + sum
                if rs <= target:
                    path.append(candidates[i])
                    backtrack(candidates, target, rs, i + 1)
                    path.pop()
                else:
                    break

        candidates.sort()
        backtrack(candidates, target, 0, 0)
        return res

6.电话号码的字母组合

给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。

给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。

示例 1:

输入:digits = “23”
输出:[“ad”,“ae”,“af”,“bd”,“be”,“bf”,“cd”,“ce”,“cf”]
示例 2:

输入:digits = “”
输出:[]
示例 3:

输入:digits = “2”
输出:[“a”,“b”,“c”]

class Solution:
    def letterCombinations(self, digits: str) -> List[str]:
        if not digits:
            return []

        Map = {
            "2": "abc",
            "3": "def",
            "4": "ghi",
            "5": "jkl",
            "6": "mno",
            "7": "pqrs",
            "8": "tuv",
            "9": "wxyz"
        }

        def backtrack(index):
            if index == len(digits):
                combinations.append("".join(combination))
            else:
                digit = digits[index]
                for letter in Map[digit]:
                    combination.append(letter)
                    backtrack(index + 1)
                    combination.pop()

        combination = []
        combinations = []
        backtrack(0)
        return combinations

7.括号生成

数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。

示例 1:

输入:n = 3
输出:["((()))","(()())","(())()","()(())","()()()"]
示例 2:

输入:n = 1
输出:["()"]

class Solution:
    def generateParenthesis(self, n: int) -> List[str]:
        result = []
        if n <= 0:
            return []

        def getParenthesis(path, left, right):
            if left == 0 and right == 0:
                result.append(path[:])
                return result

            if left == right:
                getParenthesis(path + "(", left - 1, right)
            elif left < right:
                if left > 0:
                    getParenthesis(path + "(", left - 1, right)
                getParenthesis(path + ")", left, right - 1)

        getParenthesis("", n, n)
        return result

8.单词搜索

给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false 。

单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。

示例 1:

输入:board = [[“A”,“B”,“C”,“E”],[“S”,“F”,“C”,“S”],[“A”,“D”,“E”,“E”]], word = “ABCCED”
输出:true
示例 2:

输入:board = [[“A”,“B”,“C”,“E”],[“S”,“F”,“C”,“S”],[“A”,“D”,“E”,“E”]], word = “SEE”
输出:true
示例 3:

输入:board = [[“A”,“B”,“C”,“E”],[“S”,“F”,“C”,“S”],[“A”,“D”,“E”,“E”]], word = “ABCB”
输出:false

class Solution:
    def exist(self, board: List[List[str]], word: str) -> bool:
        directions = [(0, 1), (0, -1), (1, 0), (-1, 0)]

        def check(i, j, k):
            if board[i][j] != word[k]:
                return False
            if k == len(word) - 1:
                return True
            visited.add((i, j))
            result = False
            for di, dj in directions:
                newi, nwej = i + di, j + dj
                if 0 <= newi < h and 0 <= nwej < w:
                    if (newi, nwej) not in visited:
                        if check(newi, nwej, k + 1):
                            result = True
                            break
            visited.remove((i, j))
            return result

        h = len(board)
        w = len(board[0])
        visited = set()
        for i in range(h):
            for j in range(w):
                if check(i, j, 0):
                    return True

        return False

总结

随着学校课程的开展,压力还是比较大的,平时没注意,最近观察发现,学校的课程量是上个学期的数倍多,上个学期只开了三门专业课,这个学期足足开了九门专业课,这段时间的leetcode入门明显,效率下降了很多。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值