【回溯算法】【组合问题】Leetcode 77.组合 216. 组合总和 III

【回溯算法】【回溯算法剪枝】 Leetcode 77.组合 216. 组合总和 III

  • 回溯算法可以解决的问题
  • Leetcode 77.组合
    • 解法1 回溯法三部曲,函数参数、终止条件和单层搜索逻辑
    • 解法一plus 回溯法+剪枝
  • 另一道组合回溯问题 216. 组合总和 III
    • 解法:回溯
    • 解法: 回溯+剪枝

回溯算法可以解决的问题

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

回溯模板

Leetcode 77.组合

在这里插入图片描述

---------------🎈🎈题目链接🎈🎈-------------------

解法1 回溯法三部曲,函数参数、终止条件和单层搜索逻辑

在这里插入图片描述

class Solution {List<List<Integer>> result = new ArrayList<>();  // 用于汇总单一结果作为最终结果List<Integer> path = new ArrayList<>();    // 用于存放符合条件单一结果public List<List<Integer>> combine(int n, int k) {backtracking(n,k,1);return result;}public void backtracking(int n, int k, int startindex){ // 1.确定递归函数的参数和返回值// 2.确定终止条件:当最后得到的path的大小等于k 就可以将path存入result中了 终止递归// 注意一下!!这里把path存进result的时候,不能直接存path,不然就是浅拷贝,最后result中的值都一样if(path.size() == k){result.add(new ArrayList<>(path));return;}// 3. 确定横向的单层搜索逻辑 每次搜索都是从startindex开始,startindex保证取过不再取 保证【组合】// for循环用来横向遍历,从左到右取数 取过的数字不再取。递归的过程是纵向遍历,下一层搜索要从i+1开始。// 这里i<=n是因为 数据是范围 [1, n],i就代表了数据,而不是索引for(int i = startindex; i <= n; i++){ // 控制树的横向遍历path.add(i);  // 处理节点:将i加入到path路径中backtracking(n,k,i+1); // 递归:控制树的纵向遍历,注意下一层搜索要从startindex = i+1开始path.removeLast(); // 回溯,撤销处理的节点}} 
}  

注意事项 ⭐️
注意浅拷贝和深拷贝:使用new ArrayList<>(path)
注意移除ArrayList的最后一个元素方法: path.removeLast()

时间复杂度:分析回溯问题的时间复杂度,有一个通用公式:路径长度×搜索树的叶子数。对于本题它等于 O(k⋅C(n,k))

对于给定的n个元素,从中选择k个元素的组合数是C(n, k)。每个组合的平均长度是k(即组合中有k个元素),
在这里插入图片描述

空间复杂度:O(k),递归调用栈最大深度为k(k为要生成的组合的长度)


解法一plus 回溯法+剪枝

在这里插入图片描述

注意事项 ⭐️
注意浅拷贝和深拷贝:使用new ArrayList<>(path)
注意移除ArrayList的最后一个元素方法: path.removeLast()
剪枝优化if(n-(i-startindex)<k) continue; // 剪枝操作 自己写出来所有的变量,就知道了!!!要动手

class Solution {List<List<Integer>> result = new ArrayList<>();  // 用于汇总单一结果作为最终结果List<Integer> path = new ArrayList<>();    // 用于存放符合条件单一结果public List<List<Integer>> combine(int n, int k) {backtracking(n,k,1);return result;}public void backtracking(int n, int k, int startindex){ // 1.确定递归函数的参数和返回值// 2.确定终止条件:当最后得到的path的大小等于k 就可以将path存入result中了 终止递归// 注意一下这里把path存进result的时候,不能直接存path,不然就是浅拷贝,最后result中的值都一样if(path.size() == k){result.add(new ArrayList<>(path));return;}// 3. 确定横向的单层搜索逻辑 每次搜索都是从startindex开始,startindex保证取过不再取 保证【组合】// for循环用来横向遍历,从左到右取数 取过的数字不再取。递归的过程是纵向遍历,下一层搜索要从i+1开始。// 这里i<=n是因为 数据是范围 [1, n],i就代表了数据,而不是索引for(int i = startindex; i <= n; i++){ // 控制树的横向遍历if(n-(i-startindex)<k) continue;  // 剪枝操作!!!!!!!!!!!!!!!!!!!!!!!!!!path.add(i);  // 处理节点:将i加入到path路径中backtracking(n,k,i+1); // 递归:控制树的纵向遍历,注意下一层搜索要从startindex = i+1开始path.removeLast(); // 回溯,撤销处理的节点}} 
}

另一道组合回溯问题 216. 组合总和 III

相对于77. 组合 (opens new window),无非就是多了一个限制,本题是要找到和为n的k个数的组合,而整个集合已经是固定的了[1,…,9]。

本题k相当于树的深度,9(因为整个集合就是9个数)就是树的宽度。

例如 k = 2,n = 4的话,就是在集合[1,2,3,4,5,6,7,8,9]中求 k(个数) = 2, n(和) = 4的组合。
在这里插入图片描述

解法:回溯

遍历求加和sum,sum=n时,若递归深度为k,则将当前path加入result

if(sum == n){if(path.size() == k){result.add(new ArrayList<>(path));  // 注意新建ArrayList赋值!!!!!!}return; // 如果path.size() == k 但sum != targetSum 直接返回
}

之后进行回溯,sum回溯+path回溯

class Solution {List<List<Integer>> result = new ArrayList<>();List<Integer> path = new ArrayList<>();int sum = 0;public List<List<Integer>> combinationSum3(int k, int n) {backtracking(k,n,1);return result;}public void backtracking(int k, int n, int startindex){// 终止条件if(sum == n){if(path.size() == k){result.add(new ArrayList<>(path));}return;}for(int i = startindex; i <= 9; i++){path.add(i);sum += i;backtracking(k,n,i+1);sum -= path.get(path.size()-1);  // 回溯//sum -= i;  // 回溯 这个方法也行path.removeLast(); // 回溯}}
}

解法: 回溯+剪枝

在这里插入图片描述

class Solution {List<List<Integer>> result = new ArrayList<>();List<Integer> path = new ArrayList<>();int sum = 0;public List<List<Integer>> combinationSum3(int k, int n) {backtracking(k,n,1);return result;}public void backtracking(int k, int n, int startindex){// 终止条件if(sum >n) return;  // 剪枝 如果sum已经大于n了,那就returnif(sum == n){if(path.size() == k){result.add(new ArrayList<>(path));}return;}for(int i = startindex; i <= 9; i++){path.add(i);sum += i;backtracking(k,n,i+1);sum -= i;  // 回溯path.removeLast(); //回溯}}
}

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

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

相关文章

Scratch 第十六课-弹珠台游戏

第十六课-弹珠台游戏 大家好&#xff0c;今天我们一起做一款弹珠台scratch游戏&#xff0c;我们也可以叫它弹球游戏&#xff01;这款游戏在刚出来的时候非常火爆。小朋友们要认真学习下&#xff01; 这节课的学习目标 物体碰撞如何处理转向问题。复习键盘对角色的控制方式。…

PostgreSQL10.21与PostGIS3.2.3安装文档

背景&#xff1a; 公司需要在一个服务器上装一个pg数据库&#xff0c;要求和其余服务器版本尽量保持一致&#xff0c;临时拉我装一下 特别注意&#xff1a; 需要注意的地方就是因为postgresql数据库是一个空间库&#xff0c;gis行业很多都会使用这个数据库&#xff0c;我们安…

【微信小程序】底部菜单(tabBar)

1、首先在app.json中设置pages 首页和我的页面 2、在app.json文件中添加tabar底部菜单信息 详细参数请参考文档 全局配置 | 微信开放文档

5、Linux-vi编辑器

目录 一、介绍 二、三种模式 1、命令模式&#xff08;默认&#xff09; 2、插入模式 3、末行模式 4、模式转换 三、基本操作 1、保存文件&#xff08;末行模式下&#xff09; 2、行号&#xff08;末行模式下&#xff09; 3、查找&#xff08;末行模式下&#xff09; …

详解动态规划(算法村第十九关青铜挑战)

不同路径 62. 不同路径 - 力扣&#xff08;LeetCode&#xff09; 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角&#xff08;在下图中标记为 “Finis…

软考-中级-系统集成2023年综合知识(四)

&#x1f339;作者主页&#xff1a;青花锁 &#x1f339;简介&#xff1a;Java领域优质创作者&#x1f3c6;、Java微服务架构公号作者&#x1f604; &#x1f339;简历模板、学习资料、面试题库、技术互助 &#x1f339;文末获取联系方式 &#x1f4dd; 软考中级专栏回顾 专栏…

电子签名技术如何保障电子合同的法律效力?

在当今数字化浪潮中&#xff0c;电子合同和电子签名逐渐取代了传统的纸质合同和手写签名&#xff0c;成为商业活动中的新宠。尽管如此&#xff0c;许多人对于电子签名的法律效力仍存有疑问。以下是对电子合同和电子签名相关法律效力的详细解读。 首先&#xff0c;让我们澄清什么…

数据中台:数字中国战略关键技术实施

这里写目录标题 前言为何要建设数据中台数据中台建设痛点数据中台学习资料聚焦前沿&#xff0c;方法论体系更新与时俱进&#xff0c;紧跟时代热点深入6大行业&#xff0c;提炼实践精华大咖推荐&#xff0c;数字化转型必备案头书 前言 在数字中国这一国家战略的牵引下&#xff0…

TypeScript 哲学 - everyday Type

1、 2、TypeScript a structurally typed type system. 3、 type vs interface 3、literal reference 4、non-null assertion operator

【简说八股】Redisson的守护线程是怎么实现的

Redisson Redisson 是一个 Java 语言实现的 Redis SDK 客户端&#xff0c;在使用分布式锁时&#xff0c;它就采用了「自动续期」的方案来避免锁过期&#xff0c;这个守护线程我们一般也把它叫做「看门狗」线程。 Redission是一个在Java环境中使用的开源的分布式缓存和分布式锁实…

mac报错:zsh:command not found: brew

1、基本概述&#xff1f; 在使用brew安装程序的时候MAC提示&#xff1a; zsh:command not found: brew 本质就是brew没有安装&#xff0c;这个命令与linux系统中的yum命令类似。 使用的环境说明&#xff1a; 虚拟机版本&#xff1a;VMware Workstation 17 Pro mac os Ventu…

基于springboot实现粮食仓库管理系统项目【项目源码+论文说明】

基于springboot实现粮食仓库管理系统演示 摘要 粮食作为人类生活的重要物质来源&#xff0c;在粮食流通过程中对于粮食仓库的管理不容忽视&#xff0c;随着我国粮食生产能力的提升以粮食存储管理的不断革新&#xff0c;粮食产量的增加为粮食仓储管理带来了挑战也带来了机遇&am…