【算法刷题 | 回溯思想 01】4.11(回溯算法理论、组合、组合总和 ||| )

在这里插入图片描述

文章目录

  • 回溯
  • 1.回溯算法理论基础
    • 1.1什么是回溯法?
    • 1.2回溯法的效率
    • 1.3回溯法解决的问题
    • 1.4如何理解回溯法?
    • 1.5回溯法模板
  • 2.组合
    • 2.1问题
    • 2.2解法一:暴力解法(循环次数不确定)
    • 2.3解法二:回溯
      • 2.3.1回溯思路
        • (1)回溯函数模板返回值以及参数
        • (2)回溯函数终止条件
        • (3)回溯搜索的遍历过程
      • 2.3.2代码实现
      • 2.3.3剪枝操作
  • 3.组合总和 |||
    • 3.1问题
    • 3.2解法:回溯
      • 3.2.1回溯思路
        • (1)函数返回值以及参数
        • (2)终止条件
        • (3)遍历过程
      • 3.2.2代码实现
      • 3.2.3剪枝操作

回溯

1.回溯算法理论基础

1.1什么是回溯法?

  1. 回溯法也可以叫做回溯搜索法,它是一种搜索的方式。
  2. 回溯是递归的副产品,只要有递归就会有回溯。

1.2回溯法的效率

  1. 虽然回溯法很难,很不好理解,但是回溯法并不是什么高效的算法
  2. 因为回溯的本质是穷举,穷举所有可能,然后选出我们想要的答案,如果想让回溯法高效一些,可以加一些剪枝的操作,但也改不了回溯法就是穷举的本质。

1.3回溯法解决的问题

  • 组合问题:N个数里面按一定规则找出k个数的集合
  • 排列问题:N个数按一定规则全排列,有几种排列方式
  • 切割问题:一个字符串按一定规则有几种切割方式
  • 子集问题:一个N个数的集合里有多少符合条件的子集
  • 棋盘问题:N皇后,解数独等等

补充:组合是不强调元素顺序的,排列是强调元素顺序

例如:{1, 2} 和 {2, 1} 在组合上,就是一个集合,因为不强调顺序,而要是排列的话,{1, 2} 和 {2, 1} 就是两个集合了。

1.4如何理解回溯法?

  1. 回溯法解决的问题都可以抽象为树形结构
  2. 因为回溯法解决的都是在集合中递归查找子集,集合的大小就构成了树的宽度,递归的深度就构成了树的深度
  3. 递归就要有终止条件,所以必然是一棵高度有限的树(N叉树)。

1.5回溯法模板

  • 回溯三部曲:

    • 回溯函数模板返回值以及参数(回溯算法中函数返回值一般为void)

    • 回溯函数终止条件:(搜到叶子节点了,也就找到了满足条件的一条答案,把这个答案存放起来,并结束本层递归。)

      if (终止条件) {存放结果;return;
      }
      
    • 回溯搜索的遍历过程(回溯法一般是在集合中递归搜索,集合的大小构成了树的宽度,递归的深度构成的树的深度)

      for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {处理节点;backtracking(路径,选择列表); // 递归回溯,撤销处理结果
      }
      
      • for循环就是遍历集合区间,可以理解一个节点有多少个孩子,这个for循环就执行多少次。
      • 大家可以从图中看出for循环可以理解是横向遍历,backtracking(递归)就是纵向遍历,这样就把这棵树全遍历完了,一般来说,搜索叶子节点就是找的其中一个结果了。
  • 回溯算法模板框架:

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

2.组合

2.1问题

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

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

  • 示例一:
输入:n = 4, k = 2
输出:
[[2,4],[3,4],[2,3],[1,2],[1,3],[1,4],
]
  • 示例二:
输入:n = 1, k = 1
输出:[[1]]

2.2解法一:暴力解法(循环次数不确定)

  • 使用for循环,例如示例中k为2,很容易想到 用两个for循环,这样就可以输出 和示例中一样的结果。

    for (int i = 1; i <= n; i++) {for (int j = i + 1; j <= n; j++) {cout << i << " " << j << endl;}
    }
    
  • 如果n为100,k为50呢,那就50层for循环,循环写不出来

2.3解法二:回溯

2.3.1回溯思路

  • 分解成一层一层的树形结构:

77.组合

  • 使用res存放全部合适的结果;
  • 使用paths存放当前的路径;
(1)回溯函数模板返回值以及参数
  • 回溯函数返回值一般为void;
  • 参数:
    • 题目要求 求范围[1,n]中所有可能的k个数的组合;
    • 参数有 n、k
    • 还要有一个startIndex,代表每次循环从数组第几个数开始遍历
private void backtracking(int n,int k,int startIndex)
(2)回溯函数终止条件
  • 当当前路径 path 的个数达到k时,添加到res中
if(paths.size()==k){res.add(paths);return;	
}
(3)回溯搜索的遍历过程
  • 从startIndex遍历该层的元素
for(int i=startIndex;i<=n;i++){paths.add(i);//递归backtracking(n,k,i+1);//回溯paths.remove(paths.size()-1);
}

2.3.2代码实现

	List<List<Integer>> res=new ArrayList<>();List<Integer> paths=new ArrayList<>();public List<List<Integer>> combine(int n, int k) {backtracking(n,k,1);return res;}private void backtracking(int n,int k,int startIndex){if(paths.size()==k){res.add(new ArrayList<>(paths));return;	}for(int i=startIndex;i<=n;i++){paths.add(i);//递归backtracking(n,k,i+1);//回溯paths.remove(paths.size()-1);}}

2.3.3剪枝操作

  • 回溯法虽然是暴力搜索,但也有时候可以有点剪枝优化一下的

  • 遍历代码如下:

    for(int i=startIndex;i<=n;i++){paths.add(i);//递归backtracking(n,k,i+1);//回溯paths.remove(paths.size()-1);
    }
    
  • 这个遍历的范围是可以剪枝优化的,怎么优化呢?

    • 来举一个例子,n = 4,k = 4 的话,那么第一层for循环的时候,从元素2开始的遍历都没有意义了。 在第二层for循环,从元素3开始的遍历都没有意义了。

      77.组合4

    • 如果for循环选择的起始位置之后的元素个数 已经不足 我们需要的元素个数了,那么就没有必要搜索了

  • 优化过程如下:

    • 已经选择的元素个数:path.size();
    • 还需要的元素个数为: k - path.size();
    • 在集合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]。

for(int i=startIndex;i<= n - (k - paths.size()) + 1;i++){paths.add(i);//递归backtracking(n,k,i+1);//回溯paths.remove(paths.size()-1);
}

3.组合总和 |||

3.1问题

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

  • 只使用数字1到9
  • 每个数字 最多使用一次

返回 所有可能的有效组合的列表 。该列表不能包含相同的组合两次,组合可以以任何顺序返回。

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

3.2解法:回溯

3.2.1回溯思路

(1)函数返回值以及参数
  • 无返回值
  • 参数:
    • k:总共需要k个数
    • n:总和为n
    • startIndex:从startIndex开始遍历
    • count:当前路径总和
private void backtracking(int k,int n,int startIndex,int count)
(2)终止条件
  • 判断路径个数是否为k,路径总和是否为n,满足则添加到res中并返回
if( paths.size()==k ){if(count==n){res.add(new ArrayList<>(paths));   }return;	
}
(3)遍历过程
  • 从startIndex开始递归(paths加上该节点、count总和加上)
  • 递归后回溯(paths移除最后一个节点、count总和减去该节点值)
for(int i=startIndex;i<=9;i++){paths.add(i);//递归backtracking(k,n,i+1,count+=i);//回溯paths.remove(paths.size()-1);count-=i;
}

3.2.2代码实现

	List<List<Integer>> res=new ArrayList<>();List<Integer> paths=new ArrayList<>();public List<List<Integer>> combinationSum3(int k, int n) {backtracking(k,n,1,0);return res;}private void backtracking(int k,int n,int startIndex,int count){if( paths.size()==k ){if(count==n){res.add(new ArrayList<>(paths));   }return;	}for(int i=startIndex;i<=9;i++){paths.add(i);//递归backtracking(k,n,i+1,count+=i);//回溯paths.remove(paths.size()-1);count-=i;}}

3.2.3剪枝操作

		for(int i=startIndex;i<= 9-(k-paths.size())+1 ;i++){paths.add(i);//递归backtracking(k,n,i+1,count+=i);//回溯paths.remove(paths.size()-1);count-=i;}

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

《web应用技术》第三次课后练习

实验目的&#xff1a; 1、springboot入门程序撰写并启动 2、使用postman练习参数的获取。 参考&#xff1a;Day04-10. Web入门-SpringBootWeb-快速入门_哔哩哔哩_bilibili

海外媒体发稿:新加坡 Asia One VS新加坡sg雅虎

海外媒体发稿&#xff1a;新加坡 Asia One VS新加坡sg雅虎 新加坡&#xff1a;雅虎 官网&#xff1a;sy.yahoo.com 官网&#xff1a;asiaone.com/lite 亚洲第一站。是 新加坡的新闻和生活方式网站和新闻聚合器。它是 新加坡第一个纯数字 内容平台&#xff0c;主要为新加坡、…

【C++学习】C++11新特性(第三节)——可变参数模板, lambda表达式与function包装器

文章目录 ♫文章前言♫一.可变参数模板♫1.什么是可变参数模板♫2.获取可变参数模板里参数包的方法♫3.可变参数模板在容器中的引用 ♫二. lambda表达式1. lambda表达式的由来♫2. lambda表达式♫1.lambda表达式语法♫2. 捕获列表说明 ♫3.函数对象与lambda表达式 ♫三.包装器♫…

智慧安防系统EasyCVR视频汇聚平台接入大华设备无法语音对讲的原因排查与解决

安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台支持7*24小时实时高清视频监控&#xff0c;能同时播放多路监控视频流&#xff0c;视频画面1、4、9、16个可选&#xff0c;支持自定义视频轮播。EasyCVR平台可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标…

Python爬虫怎么挣钱?6个Python爬虫赚钱方式,搞搞副业不是问题

1.最典型的就是找爬虫外包活儿 网络爬虫最通常的的挣钱方式通过外包网站&#xff0c;做中小规模的爬虫项目&#xff0c;向甲方提供数据抓取&#xff0c;数据结构化&#xff0c;数据清洗等服务。新入行的程序员大多都会先尝试这个方向&#xff0c;直接靠技术手段挣钱&#xff0…

【数据库】GROUP BY 详解、示例、注意事项

一、基本介绍 GROUP BY 语句在 SQL 中用于将来自数据库表的记录分组&#xff0c;以便可以对每个组执行聚合函数&#xff08;如 COUNT(), MAX(), MIN(), SUM(), AVG() 等&#xff09;。使用 GROUP BY 时&#xff0c;数据库会根据一个或多个列的值将结果集分为多个分组&#xff…

【Linux学习】初识Linux指令(一)

文章目录 1.指令操作与图形化界面操作1.什么是指令操作&#xff0c;什么是图形化界面操作&#xff1f; 2.Linux下基本指令1.Linux下的复制粘贴2.Linux两个who命令3.补充知识4.pwd指令5. ls 指令6.cd 指令1.目录树2.相对路径与绝对路劲3.常用cd指令 7.tree指令8. touch指令9.sta…

产品经理常用UML图之「用例图」,附7张优质实例图!

用例图是产品经理应该会画的图之一&#xff0c;它是需求分析的产物&#xff0c;借助用例图&#xff0c;参与者以可视化的方式对问题进行探讨&#xff0c;能够减少大量沟通上的障碍。接下来&#xff0c;我们一起探讨和学习一下产品经理常用的UML用例图。 一、用例图简介 用例图…

数据可视化高级技术Echarts(折线图)

目录 一、什么是折线图 二、如何实现 1.基本折线图 2.如何变得平滑只需要定义&#xff1a; smooth 3.如何定义线条的样式 color&#xff1a;设置线的颜色 width&#xff1a;设置线宽 type&#xff1a;设置线的类型 4.如何定义节点样式 symbol symbolSize&#xff1a…

2024年【T电梯修理】考试总结及T电梯修理考试技巧

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 T电梯修理考试总结考前必练&#xff01;安全生产模拟考试一点通每个月更新T电梯修理考试技巧题目及答案&#xff01;多做几遍&#xff0c;其实通过T电梯修理试题及解析很简单。 1、【多选题】修理工陶、陈&#xff0c…

在vue和 js 、ts 数据中使用 vue-i18n,切换语言环境时,标签文本实时变化

我的项目需要显示两种语言(中文和英文)&#xff0c;并且我想要切换语言时&#xff0c;页面语言环境会随之改变&#xff0c;目前发现&#xff0c;只能在vue中使用$t(‘’)的方式使用&#xff0c;但是这种方式只能在vue中使用&#xff0c;而我的菜单文件是定义在js中&#xff0c;…

neo4j使用详解(十六、集成Kerberos认证(Java/c#)——最全参考)

Neo4j系列导航&#xff1a; neo4j安装及简单实践 cypher语法基础 cypher插入语法 cypher插入语法 cypher查询语法 cypher通用语法 cypher函数语法 neo4j索引及调优 1.简介 Kerberos是一种网络身份验证协议&#xff0c;它允许网络节点在网络上证明其身份。它通过使用密钥分发中…

企业如何使用SNP Glue将SAP与Snowflake集成?

SNP Glue是SNP的集成技术&#xff0c;适用于任何云平台。它最初是围绕SAP和Hadoop构建的&#xff0c;现在已经发展为一个集成平台&#xff0c;虽然它仍然非常专注SAP&#xff0c;但可以将几乎任何数据源与任何数据目标集成。 我们客户非常感兴趣的数据目标之一是Snowflake。Sno…

uniapp 小程序获取WiFi列表

<template><view ><button click"getWifiList">获取WiFi列表</button><scroll-view:scroll-top"scrollTop"scroll-yclass"content-pop"><viewclass"itemInfo"v-for"(item, index) in wifiList&…

21. 【Android教程】评分条 RatingBar

本节将继续学习一个和进度有关的控件&#xff1a;RatingBar &#xff0c;在 Android 中 RatingBar 是一个可以支持用户打分的 UI 控件&#xff0c;相比 ProgressBar 而言&#xff0c;RatingBar 不仅仅可以用来展示同时还可以接收用户的输入操作&#xff1b;而相比 SeekBar&…

【Java面试题】MySQL上篇(索引)

文章目录 索引1.索引的分类&#xff1f;2.B树和B树的区别&#xff1f;2.1B树2.2B树 3.为什么使用索引会加快查询&#xff1f;4.创建索引的注意点&#xff1f;5.索引在哪些情况下会失效&#xff1f;6.聚簇索引和非聚簇索引的区别&#xff1f;7.回表查询是什么&#xff1f;8.什么…

flutter组件_AlertDialog

官方说明&#xff1a;A Material Design alert dialog. 翻译&#xff1a;一个材料设计警告对话框。 作者释义&#xff1a;显示弹窗&#xff0c;类似于element ui中的Dialog组件。 AlertDialog的定义 const AlertDialog({super.key,this.icon,this.iconPadding,this.iconColor,t…

IO_DAY7

1:实现2个终端之间的互相聊天 要求:千万不要做出来2个终端之间的消息发送是读一写的&#xff0c;一定要能够做到&#xff0c;一个终端发送n条消息&#xff0c;另一个终端一条消息都不回复都是没有问题的 终端A&#xff1a; #include<myhead.h> int main(int argc, char…

【LeetCode刷题笔记】LeetCode 1365.有多少小于当前数字的数字

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞 关注支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; 更多算法知识专栏&#xff1a;算法分析&#x1f525; 给大家跳段街舞感谢…

设计模式之解释器模式(上)

解释器模式 1&#xff09;概述 1.定义 定义一个语言的文法&#xff0c;并且建立一个解释器来解释该语言中的句子&#xff0c;这里的“语言”是指使用规定格式和语法的代码。 2.结构图 3.角色 AbstractExpression&#xff08;抽象表达式&#xff09;&#xff1a;在抽象表达…