有空多刷刷算法题:回溯理论基础、leecode-77:组合、leecode:组合总和 III

news2024/12/30 2:05:31

回溯算法

一、理论基础

参考代码随想录,仅作记录学习之用

  • 回溯是递归的副产品,只要有递归就会有回溯
  • 因为回溯的本质是穷举,穷举所有可能,然后选出我们想要的答案,如果想让回溯法⾼效⼀些,可以加⼀些剪枝的操作(也可能会有逻辑操作),但也改不了回溯法就是穷举的本质
  • 回溯法解决的问题都可以抽象为树形结构
  • 回溯法解决都是在集合中递归查找⼦集集合的⼤⼩就构成了树的宽度,递归的深度,都构成的树的深度
  • 递归就要有终⽌条件,所以必然是⼀棵⾼度有限的树(N叉树)

在这里插入图片描述

回溯法,⼀般可以解决如下⼏种问题

组合问题:N个数⾥⾯按⼀定规则找出k个数的集合

切割问题:⼀个字符串按⼀定规则有⼏种切割⽅式

⼦集问题:⼀个N个数的集合⾥有多少符合条件的⼦集

排列问题:N个数按⼀定规则全排列,有⼏种排列⽅式

棋盘问题:N皇后,解数独等等

二、回溯算法模板

在这里插入图片描述

    void backtracking(参数) {
        if (终⽌条件) {
            存放结果;
            return;
        }
        for (选择:本层集合中元素(树中节点孩⼦的数量就是集合的⼤⼩)) {
            处理节点;
            backtracking(路径,选择列表); // 递归
            回溯,撤销处理结果
        }
    }

77、组合

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

你可以按 任何顺序 返回答案。

示例 1:

输入:n = 4, k = 2
输出:
[ [2,4], [3,4],[2,3],[1,2],[1,3], [1,4]]

示例 2:

输入:n = 1, k = 1
输出:[[1]]

提示:

  • 1 <= n <= 20
  • 1 <= k <= n

思路:
在这里插入图片描述

class Solution {
    public List<List<Integer>> combine(int n, int k) {
        List<List<Integer>> resList = new ArrayList<>();
        if (n<k || k<1)return resList;
        // 从 1 开始是题目的设定
        Deque<Integer> path = new ArrayDeque<>();
        dfs(n,k,1,path,resList);
        return resList;
    }

    void dfs(int n, int k, int begin, Deque<Integer> path, List<List<Integer>> resList){
        // 递归终止条件是:path 的长度等于 k
        if(path.size()==k){
            resList.add(new ArrayList<>(path));
            return;
        }
        // 遍历可能的搜索起点
        for (int i=begin;i<=n;i++){
            path.addLast(i);    // 向路径变量里添加一个数
            dfs(n,k,i+1,path,resList);  // 下一轮搜索,设置的搜索起点要加 1,因为组合数理不允许出现重复的元素
            path.removeLast();  // 重点理解这里:深度优先遍历有回头的过程,因此递归之前做了什么,递归之后需要做相同操作的逆向操作
        }
    }
}

剪枝优化
在这里插入图片描述
图中每⼀个节点(图中为矩形),就代表本层的⼀个for循环,那么每⼀层的for循环从第⼆个数开始遍历的话,都没有意义,都是⽆效遍历
所以,可以剪枝的地⽅就在递归中每⼀层的for循环所选择的起始位置
如果for循环选择的起始位置之后的元素个数 已经不⾜ 我们需要的元素个数了,那么就没有必要搜索了
注意代码中i,就是for循环⾥选择的起始位置。

for (int i = startIndex; i <= n; i++) 

接下来看⼀下优化过程如下

  1. 已经选择的元素个数path.size();
  2. 还需要的元素个数为: k - path.size();
  3. 在集合n中⾄多要从该起始位置 : n - (k - path.size()) + 1,开始遍历
    为什么有个+1呢,因为包括起始位置,我们要是⼀个左闭的集合
    举个例⼦,n = 4,k = 3, ⽬前已经选取的元素为0(path.size为0),n - (k - 0) + 1 即 4 - ( 3 - 0) + 1 = 2。
    从2开始搜索都是合理的,可以是组合[2, 3, 4]。

优化后代码

    void dfs(int n, int k, int begin, Deque<Integer> path, List<List<Integer>> resList){
        // 递归终止条件是:path 的长度等于 k
        if(path.size()==k){
            resList.add(new ArrayList<>(path));
            return;
        }
        // 遍历可能的搜索起点
        for (int i=begin;i<=n-(k-path.size())+1;i++){
            path.addLast(i);    // 向路径变量里添加一个数
            dfs(n,k,i+1,path,resList);  // 下一轮搜索,设置的搜索起点要加 1,因为组合数理不允许出现重复的元素
            path.removeLast();  // 重点理解这里:深度优先遍历有回头的过程,因此递归之前做了什么,递归之后需要做相同操作的逆向操作
        }
    }
  • 时间复杂度: O(n * 2^n)
  • 空间复杂度: O(n)

216、组合总和III

找出所有相加之和为 n 的 k 个数的组合,且满足下列条件:

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

示例 1:

输入: k = 3, n = 7
输出: [[1,2,4]]
解释:
1 + 2 + 4 = 7
没有其他符合的组合了。

示例 2:

输入: k = 3, n = 9
输出: [[1,2,6], [1,3,5], [2,3,4]]
解释:
1 + 2 + 6 = 9
1 + 3 + 5 = 9
2 + 3 + 4 = 9
没有其他符合的组合了。

示例 3:

输入: k = 4, n = 1
输出: []
解释: 不存在有效的组合。
在[1,9]范围内使用4个不同的数字,我们可以得到的最小和是1+2+3+4 = 10,因为10 > 1,没有有效的组合。

提示:

  • 2 <= k <= 9
  • 1 <= n <= 60

Related Topics

  • 数组
  • 回溯

思路:
回溯三部曲:

  • 确定递归函数参数
   List<List<Integer>> resList = new ArrayList<>();
   List<Integer> tempList = new ArrayList<>();
   public void backTracking(int k, int n,int sum,int startIndex){	
  	 	n(int)⽬标和。
   		k(int)就是题⽬中要求k个数的集合。
   		sum(int)为已经收集的元素的总和,也就是path⾥元素的总和。
   		startIndex(int)为下⼀层for循环搜索的起始位置。
  • 确定终⽌条件
    k其实就已经限制树的深度,因为就取k个元素,树再往下深了没有意义。所以如果path.size() 和 k相等了,就终⽌
        if (tempList.size()==k){    //1.先满足个数
            if (sum==n){    //2.在满足和,才添加
                resList.add(new ArrayList<>(tempList));
            }
            return;
        }
  • 单层逻辑处理
    在这里插入图片描述
    剪枝优化:
    在这里插入图片描述
    代码如下:
class Solution {
    List<List<Integer>> resList = new ArrayList<>();
    List<Integer> tempList = new ArrayList<>();
    public List<List<Integer>> combinationSum3(int k, int n) {
        backTracking(k,n,0,1);
        return resList;
    }
    public void backTracking(int k, int n,int sum,int startIndex){
        //4.剪枝操作,当前值 > 目标值就没必要循环下去了
        if(sum>n){
            return;
        }
        if (tempList.size()==k){    //1.先满足个数
            if (sum==n){    //2.在满足和,才添加
                resList.add(new ArrayList<>(tempList));
            }
            return;	// 如果path.size() == k 但sum != n直接返回
        }

        for (int i=startIndex;i<=9;i++){    //3.startIndex:下一层for循环搜索的起始位置,按照题意也避免重复数字的出现了,之前从1开始到n肯定是错的,读题
            sum+=i;	 // 处理
            tempList.add(i);	// 处理
            backTracking(k,n,sum,i+1);	// 注意i+1调整startIndex
            sum-=i; // 回溯
            tempList.remove(tempList.size()-1); // 回溯
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1940355.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

华为OD机试2024年C卷D卷 - 构成指定长度字符串的个数/字符串拼接(Java)

华为OD机试&#xff08;C卷D卷&#xff09;2024真题目录 题目描述&#xff1a;构成指定长度字符串的个数 (本题分值200) 给定 M&#xff08;0 < M ≤ 30&#xff09;个字符&#xff08;a-z&#xff09;&#xff0c;从中取出任意字符&#xff08;每个字符只能用一次&#x…

PostgreSql创建触发器并增加IF判断条件

在 PostgreSQL 中&#xff0c;可以使用触发器&#xff08;Trigger&#xff09;来在表上定义自定义的插入&#xff08;INSERT&#xff09;、更新&#xff08;UPDATE&#xff09;和删除&#xff08;DELETE&#xff09;操作的行为。触发器是与表相关联的特殊函数&#xff0c;它们在…

docker的学习(二):docker常用的高级技术总结

简介 docker的一些知识点的总结 UnionFS 分层&#xff0c;轻量级&#xff0c;高性能的文件系统&#xff0c;支持一层层的叠加功能来修改文件系统。 一次同时加载多个文件系统&#xff0c;把各层文件系统叠加起来&#xff0c;最终文件系统会包含所有底层的文件和目录&#xf…

【java SE语法篇】1.运算符

目录 1. 运算符和表达式2. 算数运算符3. 隐式转换4. 强制转换5. 自增自减运算符6. 赋值运算符7. 扩展运算符8. 关系运算符9. 逻辑运算符9.1 & 和 | 的使用&#xff1a;9.2 ^&#xff08;异或&#xff09;的使用&#xff1a;9.3 !&#xff08;取反&#xff09;的使用&#x…

2024年技校大数据实验室建设及大数据实训平台整体解决方案

随着信息技术的迅猛发展&#xff0c;大数据已成为推动产业升级和社会进步的重要力量。为适应市场需求&#xff0c;培养高素质的大数据技术人才&#xff0c;技校作为职业教育的重要阵地&#xff0c;亟需加强大数据实验室的建设与实训平台的打造。本方案旨在提出一套全面、可行的…

如何制作u盘启动盘_制作U盘启动盘详细图文教程

如何制作u盘启动盘&#xff1f;一个U盘如果不做成启动盘的话&#xff0c;就只能当存储用。如果一个U盘做成启动盘的话&#xff0c;可以通过U盘启动进入PE&#xff0c;我们就可以对电脑进行重装系统或分区等一些操作使用了&#xff0c;这个主要用于电脑需要救急的情况下使用。用…

jmeter录制脚本做压力测试

1.录制 第一步 设置浏览器代理&#xff0c;我用的火狐。谷歌、IE也是都可以。 我把端口号改成8082了&#xff0c;这个无所谓的&#xff0c;只要不冲突就可以。 紧接着要往浏览器里添加证书。直接搜索证书。把jmeter的证书导入浏览器。 2.在jmeter里设置 添加线程组、http代…

Another-redis-desktop-manager+ffmpeg

一、Another-redis-desktop-manager 1.点击链接下载&#xff1a;Release v1.6.6 qishibo/AnotherRedisDesktopManager GitHub 2. 傻瓜式安装 二、ffmpeg 1.下载&#xff1a;Builds - CODEX FFMPEG gyan.dev 2.下载对应版本 3.添加环境变量&#xff1a;添加到path里&am…

Intent的基本使用

1.Intent是什么&#xff1f; Intent用于Android程序中各组件&#xff08;Activity、BroadcastReceive、Service&#xff09;的交互&#xff0c;并且可以在组件之间传递数据&#xff0c;分为显式Intent和隐式Intent。 Intent是各个组件之间信息沟通的桥梁&#xff0c;既能在Ac…

【24年7月】最新Hexo+GitHubPages搭建个人博客【一】

Hexo 是一个高效的静态网站生成器&#xff0c;使用简洁的 Markdown&#xff08;或其他模板引擎&#xff09;编写内容&#xff0c;支持丰富的插件和主题&#xff0c;允许用户轻松定制网站。它通过将文本转换为静态HTML页面&#xff0c;使得网站加载速度快&#xff0c;易于部署&a…

Linux操作系统的有关常用的命令

1.linux系统的概述 1.1 什么是Linux系统? Linux&#xff0c;全称GNU/Linux&#xff0c;是一种免费使用和自由传播的类UNIX操作系统&#xff0c;其内核由林纳斯本纳第克特托瓦 兹&#xff08;Linus Benedict Torvalds&#xff09;于1991年10月5日首次发布&#xff0c;它主要受…

塔子哥的题解点赞方案-美团2023笔试(codefun2000)

题目链接 塔子哥的题解点赞方案-美团2023笔试(codefun2000) 题目内容 塔子哥写了 n 篇题解&#xff0c;编号从 1 到 n&#xff0c;但是塔子哥忘了每篇题解有多少人点赞了。 现在他有如下两种信息&#xff1a; 1、每篇题解的点赞量都为正数&#xff0c;且不超过 m。 2、第 i 篇…

2024LitCTFmisc复现

secret 这首音乐好听&#xff0c;听完了&#xff0c;中间有段杂音 去AU看看 中间有一段藏了东西&#xff0c;放大 出flag了 flag{Calculate_Step_By_Step} 原铁&#xff0c;启动&#xff01; 解压出来是一张二维码 扫出来是原神 去010看看 看到有压缩包&#xff0c;提取出来 …

关于集成网络变压器的RJ45网口

集成网络变压器的RJ45网口是一种将网络变压器与RJ45接口集成在一起的网络连接解决方案。这种集成设计具有多项优势&#xff0c;使其在现代网络设备中得到广泛应用。 优势与特点 1. **空间节省**&#xff1a;集成设计减少了组件数量和连接线缆长度&#xff0c;有助于节省设备内…

Adobe Premiere Pro(Pr)安装包软件下载

一、简介 Adobe Premiere Pro&#xff08;简称Pr&#xff09;是由Adobe公司开发的一款功能强大的视频编辑软件。它支持多平台使用&#xff0c;包括Windows和Mac系统&#xff0c;并且拥有良好的兼容性和高效的性能。Premiere Pro不仅提供了视频剪辑、特效添加、音频处理等基本功…

监控易V7.6.6.15全新升级14:设置功能全面优化

随着企业IT架构的不断发展&#xff0c;对运维管理的需求也日益增加。为了满足广大用户对运维管理的更高需求&#xff0c;监控易系统近期完成了一次重要版本升级。本次升级在原有功能的基础上&#xff0c;对设置功能进行了全面优化和新增&#xff0c;旨在为用户提供更加灵活、高…

系统架构师(每日一练5)

每日一练 1.某企业准备将四个工人甲、乙、丙、丁分配在A、B、C、D四个岗位。每个工人由于技术水平不同&#xff0c;在不同岗位上每天完成任务所 需的工时见下表。适当安排岗位&#xff0c;可使四个工人以最短的总工时()全部完成每天的任务。答案与解析 ABCD甲7523乙9437丙547…

【每日一练】python编写一个简易计算器

程序代码: #循环语句&#xff0c;条件为真所以循环执行 while True: #定义两个数的变量和运算符号 num1 float(input("第一个数:")) num2 float(input("第一个数:")) syminput("选择运算符 - * /&#xff1a;") #判断运算符号 …

《python语言程序设计》第6章2题(求一个整数各个数字的和)编写一个函数

求一个整数各个数字的和编写一个函数&#xff0c;计算一个整数各个数字的和&#xff0c; def sumDigits(n):a n // 100b n % 100 // 10c n % 100 % 10print(f"{n}数&#xff0c;分成个&#xff0c;十&#xff0c;百&#xff0c;{a}{b}{c}", a b c)sumDigits(23…

算法类学习笔记 ———— 红绿灯检测

文章目录 介绍基于传统视觉方法的检测基于颜色和边缘信息基于背景抑制 基于深度学习的检测特征金字塔网络&#xff08;FPN&#xff09;红绿灯检测特征金字塔自下而上自上而下横向连接 特征融合SSD红绿灯检测 高精度地图结合 介绍 红绿灯检测就是获取红绿灯在图像中的坐标以及它…