代码随想录-回溯(组合问题)|ACM模式

news2025/1/16 17:42:38

目录

前言:

77.组合

题目描述:

输入输出示例:

思路和想法:

216. 组合总和 III

题目描述:

输入输出示例:

思路和想法:

17. 电话号码的字母组合

题目描述:

输入输出描述:

思路和想法:

40. 组合总和 II

题目描述:

输入输出描述:

思路和想法:


前言:

这里对于组合问题,进行了深入的探讨(ACM模式):

  • 数组集合里元素不重复,元素只能取一次,组合不许重复
  • 引入总和统计
  • 引入map哈希
  • 引入去重的概念---(数组集合里元素有重复,元素只能取一次,但组合不许重复)

77.组合

题目描述:

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

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

输入输出示例:

示例1:

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

示例2:

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

提示:

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

思路和想法:

回溯法的问题,都可以抽象为树形结构问题。

回溯法解决的是在集合中递归查找子集,集合的大小构成树的宽度,递归的深度构成树的深度。

这道题目属于组合问题的模板题。

#include <bits/stdc++.h>

using namespace std;
/*
* 作者:希希雾里
* 77.组合
* */

/*
* 这里我们能够比较清晰的,要使用回溯。
* */
vector<vector<int>> result;
vector<int> path;
//这里对于回溯要传入的参数:元素数量,限定条件以及要开始遍历的元素
//这里能够比较清晰的知道n即为回溯的宽度,k即为回溯的深度。
void backtracing(int n, int k, int startIndex){
    /*终止条件*/
    if(path.size() == k){
        result.push_back(path);
        return;
    }
    /*处理节点 + 回溯撤销*/
    for (int i = startIndex; i <= n; ++i) {
        path.push_back(i);
        backtracing(n, k, i+1);
        path.pop_back();
    }
};

int main() {
    int n, k;
    cin>> n >> k;
    result.clear();
    path.clear();
    backtracing(n, k,1);

    //结果输出
    for (int i = 0; i < result.size(); ++i) {
        for (int j = 0; j < result[i].size(); ++j) {
            cout << result[i][j];
            if(j != result[i].size() - 1) cout << " ";
        }
        //注意最后输出不需要换行。
        if(i == result.size() - 1) return 0;
        cout << endl;
    }
    return 0;
}

/*  测试样例
4 2

1 1
*
* */

216. 组合总和 III

题目描述:

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

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

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

输入输出示例:

示例1:

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

示例2:

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

示例3:

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

提示:

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

思路和想法:

这道题目和上一道题基本一致,在原有基础上,还需要统计path里元素的总和,终止条件发生了改变, path.size() == k && sum == n 。

#include <bits/stdc++.h>

using namespace std;
/*
* 作者:希希雾里
* 216.组合总和III
* */
vector<vector<int>> result;
vector<int> path;
int sum = 0;
//这里对于回溯要传入的参数,集合个数,目标总和以及要遍历的元素下标
void backtracing(int k, int n, int startIndex){
    /*终止条件*/
    if(path.size() == k && sum == n){
        result.push_back(path);
        return;
    }
    /*处理节点 + 回溯撤销*/
    for (int i = startIndex; i <= 9; ++i) {
        path.push_back(i);
        sum += i;
        backtracing(n, k, i + 1);
        sum -= path.back();
        path.pop_back();
    }
};

int main() {
    int n, k;
    cin>> n >> k;
    result.clear();
    path.clear();
    backtracing(k, n,1);

    //结果输出
    for (int i = 0; i < result.size(); ++i) {
        for (int j = 0; j < result[i].size(); ++j) {
            cout << result[i][j];
            if(j != result[i].size() - 1) cout << " ";
        }
        //注意最后输出不需要换行。
        if(i == result.size() - 1) return 0;
        cout << endl;
    }
    return 0;
}

17. 电话号码的字母组合

题目描述:

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

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

输入输出描述:

示例1:

输入:digits = "23" 输出:["ad","ae","af","bd","be","bf","cd","ce","cf"]

示例2:

输入:digits = "" 输出:[]

示例3:

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

提示:

  • 0 <= digits.length <= 4
  • digits[i] 是范围 ['2', '9'] 的一个数字

思路和想法:

这里首先构建数字和字符之间的映射,后续就是组合问题,采用回溯方法就可以解决了。

#include <bits/stdc++.h>

using namespace std;
/*
* 作者:希希雾里
* 17.电话号码的字母组合
* */
vector<string> result;
string s;
//构建map,建立映射
const string map_letter[10] = {
"",
"",
"abc",
"def",
"ghi",
"jkl",
"mno",
"pqrs",
"tuv",
"wxyz",
};

/*
* 函数:          backtracing()
* 输入参数:       digits:输入的字符串    index:字符串元素下标 
* */
void backtracing(const string & digits, int index){
    /*终止条件*/
    if(index == digits.length()){
        result.push_back(s);
        return;
    }
    int digit = digits[index] - '0';
    string letters = map_letter[digit];
    /*处理节点 + 回溯过程*/
    for (int i = 0; i < letters.length(); ++i) {
        s.push_back(letters[i]);
        backtracing(digits, index + 1);
        s.pop_back();
    }
};

int main() {
    result.clear();
    s.clear();
    //字符串输入
    string str;
    getline(cin,str);

    backtracing(str, 0);
    //结果输出
    for (int i = 0; i < result.size(); ++i) {
        //注意最后输出不需要换行。
        cout << result[i];
        if(i == result.size() - 1) return 0;
        cout << endl;
    }
    return 0;
}

/*  测试样例
23

2
*
* */

40. 组合总和 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] ]

提示:

  • 1 <= candidates.length <= 100
  • 1 <= candidates[i] <= 50
  • 1 <= target <= 30

思路和想法:

这道题目和之前不一样的地方在于,要取的数组里有数值相等的元素并且要求解集不能包含重复的组合。所以这道题目涉及到了去重。

一个组合里可以有重复的元素,即不需要树枝去重(纵向)。不能有重复的组合,即要进行树层去重(横向)。

树层去重和树枝去重,是根据树形结构,提出的去重概念。

那么转换到具体实现上,需要解决两个问题:

  • 如何实现去重?这里先对数组进行排序,将重复的元素紧挨在一起,之后遍历时判断与前面的元素是否相等即可。
  • 如何分辨树层去重和树枝去重?这里采用一个bool数组used,used[i - 1] == true,说明同一树枝candidates[i - 1]使用过,used[i - 1] == false,说明同一树层candidates[i - 1]使用过。
#include <bits/stdc++.h>

using namespace std;
/*
* 作者:希希雾里
* 40. 组合总和 II
* */
vector<vector<int>> result;
vector<int> path;
int sum = 0;

/*
* 函数:          backtracing()
* 输入参数:       candidates:输入的数组    target: 目标数值     index:字符串元素下标       used:标志数组
* */
void backtracing(vector<int>& candidates, int target, int index, vector<bool>& used){
    if(sum == target){
        result.push_back(path);
        return;
    }
    for(int i = index; i < candidates.size();++i){
        if(i > 0 && candidates[i] == candidates[i - 1] && used[i - 1] == false){
            continue;
        }
        path.push_back(candidates[i]);
        sum += candidates[i];
        used[i] = true;
        backtracing(candidates, target, i + 1, used);
        used[i] = false;
        sum -= candidates[i];
        path.pop_back();
    }
};

int main() {
    result.clear();
    path.clear();

    vector<int> candidates;
    int n;
    while(cin >> n){
        candidates.push_back(n);
        if(getchar() == '\n'){
            break;
        }
    }
    int target;
    cin >> target;
    vector<bool> used(candidates.size(),false);

    //默认升序排序
    sort(candidates.begin(),candidates.end());

    backtracing(candidates, target, 0, used);
    //结果输出
    for (int i = 0; i < result.size(); ++i) {
        for (int j = 0; j < result[i].size(); ++j) {
            cout << result[i][j];
            if(j != result[i].size() - 1) cout << " ";
        }
        //注意最后输出不需要换行。
        if(i == result.size() - 1) return 0;
        cout << endl;
    }
    return 0;
}

/*  测试样例
10 1 2 7 6 1 5
8

2 5 2 1 2
5
*
* */

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

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

相关文章

MODBUS TCP转CCLINK IE协议网关profinet接口和以太网接口的区别

你是否曾经遇到过需要将不同的设备连接到一个统一的网络中&#xff1f;或者你是否曾经遇到过设备之间的通讯协议不兼容的问题&#xff1f;远创智控的YC-CCLKIE-TCP通讯网关就是为解决这些问题而设计的。 YC-CCLKIE-TCP通讯网关是一款自主研发的CCLINK IE FIELD BASIC从站功能…

OpenAI报错 time out:HTTPSConnectionPool(host=‘api.openai.com‘, port=443)

项目场景&#xff1a; 使用openai的api调用chatGPT报错&#xff0c;同样的代码在另一台机器没有问题 问题描述 使用官方示例 import openaiopenai.api_key sk-xxxx def chat_gpt(prompt):prompt promptmodel_engine "text-davinci-003"completion openai.Comp…

【Default config not found for ApplicationConfig】的一种解决方案

&#x1f4a7; 记录一下今天遇到的 b u g \color{#FF1493}{记录一下今天遇到的bug} 记录一下今天遇到的bug&#x1f4a7; &#x1f337; 仰望天空&#xff0c;妳我亦是行人.✨ &#x1f984; 个人主页——微风撞见云的博客&#x1f390; &#x1f433; 《数据结构与算…

vue项目之《 搭建路由系统 》

author&#xff1a;德玛玩前端 date&#xff1a;2023-07-22 今天&#xff0c;在工作中拿到了架构师的前端框架&#xff0c;是一个vue2elementui搭建的单页面架构&#xff0c;没有路由系统&#xff0c;需要自己搭建&#xff0c;因为以往拿到的框架都是路由系统已经搭建好&#x…

数据结构初阶--单链表

目录 一.单链表的定义 二.单链表的分类 2.1.不带头结点的单链表 2.2.带头结点的单链表 三.单链表的功能实现 3.1.单链表的定义 3.2.单链表的打印 3.3.单链表的结点的创建 3.4.单链表的尾插 3.5.单链表的头插 3.6.单链表的尾删 3.7.单链表的头删 3.8.单链表的查找 …

【Vue3】Vue3核心内容(上)

&#x1f380;个人主页&#xff1a;努力学习前端知识的小羊 感谢你们的支持&#xff1a;收藏&#x1f384; 点赞&#x1f36c; 加关注&#x1fa90; 文章目录 常用的Composition APIsetup函数ref函数reactive函数vue3中的响应式原理vue2的响应式Vue3的响应式 reactive对比Refse…

数据结构---手撕图解七大排序(含动图演示)

文章目录 插入排序直接插入排序希尔排序 选择排序选择排序堆排序 交换排序冒泡排序快速排序hoare版挖坑法前后指针法快速排序的递归展开图快速排序的优化三数取中法 快速排序的非递归实现 归并排序 插入排序 插入排序分为直接插入排序和希尔排序&#xff0c;其中希尔排序是很值…

xxl-job分布式任务调度器的学习

先看一下原生的任务调度器 package com.xxl.job.executor.service.jobhandler;import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component;Compone…

3.Docker网络和资源控制

文章目录 Docker操作二Docker网络实现原理端口映射查看日志 网络模式host模式container模式none模式bridge模式自定义网络 Docker资源控制CPU资源控制设置CPU使用率上限设置CPU资源占用比&#xff08;设置多个容器才有效&#xff09;设置容器绑定指定CPU 内存使用限制设置磁盘I…

RK3399移植u-boot

RK3399移植u-boot 0.前言一、移植1.交叉工具链安装2.获取bl31.elf3.移植u-boot1)下载&#xff1a;2)配置&#xff1a;修改串口波特率&#xff1a;修改emmc&#xff1a;配置FIT&#xff1a;配置boot delay&#xff1a;(可选) 3)编译&#xff1a;4)生成idbloader.img文件&#xf…

使用 Docker 快速上手中文版 LLaMA2 开源大模型

本篇文章&#xff0c;我们聊聊如何使用 Docker 容器快速上手朋友团队出品的中文版 LLaMA2 开源大模型&#xff0c;国内第一个真正开源&#xff0c;可以运行、下载、私有部署&#xff0c;并且支持商业使用。 写在前面 感慨于昨天 Meta LLaMA2 模型开放下载之后&#xff0c;Git…

实验五 分支限界法

实验五 分支限界法 01背包问题的分治限界法的实现 剪枝函数 限界函数 1.实验目的 1、理解分支限界法的剪枝搜索策略&#xff0c;掌握分支限界法的算法框架 2、设计并实现问题&#xff0c;掌握分支限界算法。 2.实验环境 java 3.问题描述 给定n种物品和一背包。物品i的重…

JMeter基础入门教程之CSV数据文件设置CSV Data Set Config

最近在做压力测试&#xff0c;登录功能用到了配置元件&#xff1a;CSV 数据文件设置&#xff0c;可以将登录用户名和密码放在一个csv文件中&#xff0c;然后通过CSV数据文件设置元件读取出来&#xff0c;用来做压测。 一、CSV文件 CSV文件小知识分享&#xff1a;是指"逗号…

Linux内核--内存管理

MMU的产生背景 在计算机出现的早期&#xff0c;其内存资源十分有限&#xff0c;一般只有几十几百KB&#xff0c;当时的程序规模也小&#xff0c;对于当时的程序而言&#xff0c;KB级的内存资源尚足够使用。但随着计算机技术的发展&#xff0c;应用程序的规模不断膨胀&#xff…

k8s部署wordpress+mysql博客平台

k8s部署wordpressmysql博客平台 1、yaml文件准备1.1 wordpress-db.yaml1.2 wordpress.yaml 2、部署安装2.1 先创建wordpress命名空间2.2 部署wordpress-db2.3部署wordpress 3、访问测试 1、yaml文件准备 1.1 wordpress-db.yaml apiVersion: apps/v1kind: Deploymentmetadata:…

【flink】ColumnarRowData

列式存储 在调试flink读取parquet文件时&#xff0c;读出来的数据是ColumnarRowData&#xff0c;由于parquet是列式存储的文件格式&#xff0c;所以需要用一种列式存储的表示方式&#xff0c;ColumnarRowData就是用来表示列式存储的一行数据&#xff0c;它包含多个数组的数据结…

Matlab求解基于RRT算法的自定义垛型的路径避障

目录 背景 1 RRT搜索算法 2 基于Matlab的RRT搜索算法 3 基于Matlab的自定义垛型绘制 4 基于RRT算法的自定义垛型的路径避障 背景 在码垛机械臂路径规划过程中&#xff0c;需要根据现有箱子的码垛状态&#xff0c;给出下一个箱子的最佳码放无碰撞路径。RRT 快速搜索随机…

vue2项目 自定义详情组件

vue2项目 自定义详情组件 效果组件代码组件引入以及传参格式寄语 效果 组件代码 DetailFormRow.vue已经封装好&#xff0c;根据数据格式直接引用即可。 <template><div class"detail-form"><el-row class"detail-form-row" style"ma…

基本函数、常见曲线图像

基本函数图像是指一些常见的数学函数的图像&#xff0c;这些函数在数学和工程等领域中经常被使用。下面是一些常见的基本函数及其图像&#xff1a; 参考文献&#xff1a;同济版高等数学【第七版】上下册教材

几张表格搞定Mysql的SQL语句

一、数据库的登录与退出 登录Mysqlmysql -uroot -p123退出Mysqlexit 二、对数据库的操作 查询所有数据库show databases;创建数据库create database 数据库名字;删除数据库drop database 数据库名字;查询创建数据库的具体语句show create database 数据库名字;使用数据库use…