当前位置: 首页 > news >正文

力扣系列题,回溯专场

力扣系列题

https://leetcode.cn/problems/permutations/solution/hui-su-suan-fa-python-dai-ma-java-dai-ma-by-liweiw/

做回溯的最关键的问题:1、递归参数是什么,2、终止条件是什么
46. 全排列(中等)
47. 全排列 II(中等):思考为什么造成了重复,如何在搜索之前就判断这一支会产生重复;
39. 组合总和(中等)
40. 组合总和 II(中等)
77. 组合(中等)
78. 子集(中等)
90. 子集 II(中等):剪枝技巧同 47 题、39 题、40 题;
60. 第 k 个排列(中等):利用了剪枝的思想,减去了大量枝叶,直接来到需要的叶子结点;
93. 复原 IP 地址(中等)

全排列

  1. 全排列
    给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。

递归参数为数组中是否被使用的标志
终止条件为path的大小等于nums

class Solution:
    def permute(self, nums: List[int]) -> List[List[int]]:
        path = []
        res = []
        def dfs(used):
            if len(path) == len(nums):
                res.append(path[:])
            for j in range(len(nums)):
                if used[j] == True: continue
                path.append(nums[j])
                used[j] = True
                dfs(used)
                path.pop()
                used[j] = False
        used = [False for _ in range(len(nums))]
        dfs(used)
        return res
  1. 全排列 II
    给定一个可包含重复数字的序列 nums ,按任意顺序 返回所有不重复的全排列。

需要对重复的排列进行剪枝
与上题的唯一差异就在于多了剪枝判断

class Solution:
    def permuteUnique(self, nums: List[int]) -> List[List[int]]:
        used = [False for _ in range(len(nums))]
        path = []
        res = []

        def dfs(used):
            if len(path) == len(nums): 
                res.append(path[:])
                return
            for i in range(len(nums)):
                if used[i]: continue
                if i>0 and nums[i] == nums[i-1] and used[i-1] == False: continue
                path.append(nums[i])
                used[i] = True
                dfs(used)
                used[i] = False
                path.pop()
        used = [False for _ in range(len(nums))]
        nums.sort()
        dfs(used)
        return res

组合

  1. 组合
    给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。

直接递归就可以

class Solution:
    def combine(self, n: int, k: int) -> List[List[int]]:
        res = []
        path = []
        def dfs(i):
            if len(path) == k:
                res.append(path[:])
            for j in range(i,n+1):
                path.append(j)
                dfs(j+1)
                path.pop()
        dfs(1)
        return res
  1. 组合总和
    给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。
    candidates 中的 同一个 数字可以 无限制重复被选取 。如果至少一个数字的被选数量不同,则两种组合是不同的。
    对于给定的输入,保证和为 target 的不同组合数少于 150 个

递归和dp相辅相成,此题既可以用递归暴力,也可以使用dp来求解。但是注意的是,dp返回的是组合的数量,无法返回组合分别是什么
递归参数:target
终止条件: target==0
难点是在于如何对重复的结果进行剪枝,保持有序搜索,在搜索的过程中去重

class Solution:
    def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
        path = []
        res = []
        def dfs(j,target):
            if target == 0: 
                res.append((path[:]))
            if target<0: return 
            for i in range(j,len(candidates)):
                path.append(candidates[i])
                dfs(i,target - candidates[i])
                path.pop()
        dfs(0,target)
        return res
  1. 组合总和 II
    给定一个候选人编号的集合 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
    candidates 中的每个数字在每个组合中只能使用 一次 。

是用排序+used来剔除重复遍历的情况,由于是每个数字只能使用一次,所以递归参数为j+1而非上一题的j。

class Solution:
    def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
        path = []
        res = []
        def dfs(i,target,used):
            if target == 0:
                res.append(path[:])
                return
            if target <0:
                return
            for j in range(i,len(candidates)):
                if j>0 and candidates[j] == candidates[j-1] and used[j-1] == False: continue
                path.append(candidates[j])
                used[j] = True
                dfs(j+1,target-candidates[j],used)
                path.pop()
                used[j] = False
        candidates = sorted(candidates)
        used = [False for _ in range(len(candidates))]
        dfs(0,target,used)
        return res
  1. 组合总和 III
    找出所有相加之和为 n 的 k 个数的组合,且满足下列条件:

只使用数字1到9
每个数字 最多使用一次
返回 所有可能的有效组合的列表 。该列表不能包含相同的组合两次,组合可以以任何顺序返回。

class Solution:
    def combinationSum3(self, k: int, n: int) -> List[List[int]]:
        res  = []
        path = []
        def dfs(i):
            if sum(path) == n and len(path) == k:
                res.append(path[:])
                return 
            if len(path)>=k: return 
            for j in range(i,10):
                path.append(j)
                dfs(j+1)
                path.pop()
        dfs(1)
        return res
  1. 组合总和 Ⅳ
    给你一个由 不同 整数组成的数组 nums ,和一个目标整数 target 。请你从 nums 中找出并返回总和为 target 的元素组合的个数。

题目数据保证答案符合 32 位整数范围。

这题也可以利用递归来求解,但是时间复杂度太高。可以通过dp的方式快速求解得到
使用dp时要注意内外层循环,外层时targte,内层时nums,直接使用一维dp即可

class Solution:
    def combinationSum4(self, nums: List[int], target: int) -> int:
        res = []
        path = []
        def dfs(i,target):
            if target == 0: 
                res.append(path[:])
                return
            if target<0:
                return 
            for j in range(len(nums)):
                path.append(nums[j])
                dfs(j,target - nums[j])
                path.pop()
        dfs(0,target)
        return len(res)
class Solution:
    def combinationSum4(self, nums: List[int], target: int) -> int:
        dp = [0 for _ in range(target+1)]
        dp[0] = 1
        for j in range(target+1):
            for i in range(len(nums)):
                if j-nums[i]>=0:
                    dp[j] += dp[j-nums[i]]
        return dp[-1]
  1. 子集
    给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。
    解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。
class Solution:
    def subsets(self, nums: List[int]) -> List[List[int]]:
        res = []
        def dfs(i,path):
            res.append(path[:])
            for j in range(i,len(nums)):
                path.append(nums[j])
                dfs(j+1,path)
                path.pop()
        dfs(0,[])
        return res
  1. 子集 II
    给你一个整数数组 nums ,其中可能包含重复元素,请你返回该数组所有可能的子集(幂集)。

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

剪枝,去重,和之前的处理策略是一致的

class Solution:
    def subsetsWithDup(self, nums: List[int]) -> List[List[int]]:
        res = []
        used = [False for _ in range(len(nums))]
        def dfs(i,path,used):
            res.append(path[:])
            for j in range(i,len(nums)):
                if j>0 and nums[j] == nums[j-1] and used[j-1]  == False: continue
                path.append(nums[j])
                used[j] = True
                dfs(j+1,path,used)
                path.pop()
                used[j] = False
        nums = sorted(nums)
        dfs(0,[],used)
        return res

相关文章:

  • 在windows桌面上部署网站
  • 8月更新 | Visual Studio Code Python
  • 猿创征文 |【算法面试入门必刷】动态规划-线性dp(一)
  • 一整套美团面经(给对象超用心整理的)
  • 【机器学习】鸢尾花数据的基本信息 || sklearn
  • Opencv项目实战:07 人脸识别和考勤系统
  • SpringBoot入门教程:数据库恢复(mysqldump和mysqlbinlog)
  • 内网开发新项目之流程记录
  • 数据分析-numpy2
  • MATLAB | 全网唯一,双变量及三变量映射图表的MATLAB绘制
  • 分布式 | 从 dble 日志分析到 MySQL 源码学习
  • 天呐,我居然可以隔空作画了
  • 【面试】软件自动化测试岗位面试题和答案
  • 氨基功能化离子液体修饰SBA-15(NH2-IL-SBA)|含有烯丙基的离子液体氯化1-烯丙基-3-甲基咪唑(AMIMCl)
  • 【c ++ primer 笔记】第 14章 重载运算符
  • 4. 路由到控制器 - Laravel从零开始教程
  • ECS应用管理最佳实践
  • iOS 颜色设置看我就够了
  • Java深入 - 深入理解Java集合
  • KMP算法及优化
  • Spring-boot 启动时碰到的错误
  • Unix命令
  • Vue--数据传输
  • win10下安装mysql5.7
  • 对话:中国为什么有前途/ 写给中国的经济学
  • 湖南卫视:中国白领因网络偷菜成当代最寂寞的人?
  • 聚簇索引和非聚簇索引
  • 浅谈JavaScript的面向对象和它的封装、继承、多态
  • 使用 5W1H 写出高可读的 Git Commit Message
  • 使用Gradle第一次构建Java程序
  • 使用阿里云发布分布式网站,开发时候应该注意什么?
  • ​iOS安全加固方法及实现
  • ​如何使用ArcGIS Pro制作渐变河流效果
  • #AngularJS#$sce.trustAsResourceUrl
  • %3cscript放入php,跟bWAPP学WEB安全(PHP代码)--XSS跨站脚本攻击
  • ( 10 )MySQL中的外键
  • (2)nginx 安装、启停
  • (4)Elastix图像配准:3D图像
  • (草履虫都可以看懂的)PyQt子窗口向主窗口传递参数,主窗口接收子窗口信号、参数。
  • (超简单)构建高可用网络应用:使用Nginx进行负载均衡与健康检查
  • (附源码)springboot掌上博客系统 毕业设计063131
  • (三)Honghu Cloud云架构一定时调度平台
  • (转)平衡树
  • ../depcomp: line 571: exec: g++: not found
  • ./configure,make,make install的作用(转)
  • .equal()和==的区别 怎样判断字符串为空问题: Illegal invoke-super to void nio.file.AccessDeniedException
  • .NET Framework 3.5中序列化成JSON数据及JSON数据的反序列化,以及jQuery的调用JSON
  • .Net 代码性能 - (1)
  • .NetCore实践篇:分布式监控Zipkin持久化之殇
  • .NET处理HTTP请求
  • .NET项目中存在多个web.config文件时的加载顺序
  • .NET中GET与SET的用法
  • .net中生成excel后调整宽度
  • /usr/local/nginx/logs/nginx.pid failed (2: No such file or directory)
  • ?