回溯算法【组合 子集 全排列 N皇后】

 大家好,最近一直在写算法,刷了力扣中部分回溯,总结了大致题型和思路,在这里分享给大家,希望大家可以有所收获!!!

目录

回溯算法的基本思想:

回溯的典型结构:

算法思路讲解:

1. 组合

2.子集:

3.全排列:

4.N皇后:


什么是回溯???

回溯就是一种通过递归解决问题的算法思想,这种方法适用于那些需要穷举所有可能的复杂问题,比如排列,组合,子集,棋盘等,因为回溯是通过递归实现的,所以回溯理解起来也比较困难,并且在时间复杂度上也比较高,它的复杂度通常是指数级别 O(2^n)阶乘级别 O(n!)。虽然可以通过剪枝来减少搜索空间,但总体而言,回溯在大规模问题上效率不高

回溯算法的基本思想:

回溯算法的核心思想:尝试所有的可能,当发现某一解不符合时,就进行回退到上一步,然后选择其他路径,直到遍历所有可能

回溯的典型结构:

以递归的形式出现,每一步尝试都会进入递归分支,直到找到合适的解或者发现需要回退

void backtrack(参数) {if (满足结束条件) {// 找到解return;}for (所有可能的选择) {做出选择;递归调用 backtrack(新的参数);撤销选择(回溯);}
}

算法思路讲解:

1. 组合

题目链接:77. 组合 - 力扣(LeetCode)

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

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

示例 1:

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

解释:找[1,4]范围内的数中两个数的组合

定义一个全局result,将它当做参数进行传递,然后通过遍历将解添加到result当中,然后进行返回 

思路:

因为我们返回的是一个一个二维容器,所以我们需要一维容器进行填充,因此我们主要操作的是一维容器而不是二维容器,二维是我们一维在符合条件时进行添加的

详细代码流程:

ans=[ ]不符合条件,进入第一个for循环,startIndex=1,将 i 添加到ans中,进入getResult()当中

ans=[ 1 ]不符合条件,进入第二个for循环,startIndex=2,将2进行添加上去,进入getResult()当中

ans=[ 1,2 ]符合条件,将ans添加到result当中,返回第二个for循环的getResult()位置,然后进行尾删,删除2,i+1=3,将3添加到ans当中,进入getResult()当中

ans=[ 1,3 ]符合条件,将ans添加到result当中,回到第二个for循环的getResult()位置,然后进行尾删,删除3,i+1=4,将4添加到ans当中,进入getResult()当中

ans=[ 1,4 ]符合条件,将ans添加到result当中,回到第二个for循环的getResult()位置,然后进行尾删,删除4,第二个for循环循环完毕,回到第一个for循环的getResult()位置,然后进行尾删,i+1=2,添加2,ans=[2],然后进入到getResult()当中,ans不符合条件,开始第三for循环......(同上)

                         []/   |   |   \[1]    [2]  [3]  [4]/   \     |    |[1,2] [1,3]  [2,3] [3,4]|     |      |[1,4]  [1,4]  [2,4]

 大家可以结合上面的两个,相信已经表明的很清楚了

class Solution {vector<vector<int>> result;vector<int> ans;public:void getResult(int n, int k, int startIndex) {if (ans.size() == k) {result.push_back(ans);return;}for (int i = startIndex; i <= n - (k - ans.size()) + 1; i++) {ans.push_back(i);getResult(n, k, i + 1);ans.pop_back();}}public:vector<vector<int>> combine(int n, int k) {getResult(n, k, 1);return result;}
};

 以下是关于 i <= n - (k - ans.size()) + 1的剪枝操作

  1. 已经选择的元素个数:path.size();
  2. 所需需要的元素个数为: k - path.size();
  3. 列表中剩余元素(n-i) >= 所需需要的元素个数(k - path.size())
  4. 在集合n中至多要从该起始位置 : i <= n - (k - path.size()) + 1,开始遍历
  5. 为什么有个+1呢,因为包括起始位置,我们要是一个左闭的集合。
  6. 举个例子,n = 4,k = 3, 目前已经选取的元素为0(path.size为0),n - (k - 0) + 1 即 4 - ( 3 - 0) + 1 = 2。
  7. 从2开始搜索都是合理的,可以是组合[2, 3, 4]。
2.子集:

题目链接:78. 子集 - 力扣(LeetCode)

给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的

子集(幂集)。

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

示例 1:

输入:nums = [1,2,3]输出:[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]

 子集思路和组合相似,这里就不详细讲解,下面是实现流程

                              [ ]/     |    \[1]       [2]    [3]/    \     /   \  [1,2]  [1,3] [2,3] [2]    /                [1,2,3]          
void getResult(vector<int>& nums, int startIndex) {if (startIndex<=nums.size()) {result.push_back(ans);}for (int i = startIndex; i < nums.size(); i++) {ans.push_back(nums[i]);getResult(nums, i + 1);ans.pop_back();}}
3.全排列:

题目链接:46. 全排列 - 力扣(LeetCode)

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

示例 1:

输入:nums = [1,2,3]输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]] 

                          [1, 2, 3]/          |          \[1, 2, 3]        [1, 3, 2]         [2, 1, 3]|                  |               |/       \          /      \         /      \
[1, 2, 3] [1, 3, 2]  [2, 1, 3] [2, 3, 1] [3, 1, 2] [3, 2, 1]
 void getResult(vector<int>& nums, int startIndex) {if (startIndex == nums.size()) {result.push_back(nums);return;}for (int i = startIndex; i < nums.size(); i++) {swap(nums[startIndex], nums[i]);getResult(nums, startIndex + 1);swap(nums[startIndex], nums[i]);}}
4.N皇后:

题目链接:51. N 皇后 - 力扣(LeetCode)

按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。

n 皇后问题 研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。

给你一个整数 n ,返回所有不同的 n 皇后问题 的解决方案。

每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 'Q' 和 '.' 分别代表了皇后和空位。 

示例 1:

输入:n = 4输出:[[".Q..","...Q","Q...","..Q."],["..Q.","Q...","...Q",".Q.."]]解释:如上图所示,4 皇后问题存在两个不同的解法。

初始状态:

[ . . . . ]

[ . . . . ]

[ . . . . ]

[ . . . .

第一层递归 (row = 0): - 尝试在第 0 行的每一列放置皇后。 - 选择在 (0, 0) 放置 Q。

[ Q . . . ]

[ . . . . ]

[ . . . . ]

[ . . . . ]

第二层递归 (row = 1): - 尝试在第 1 行的每一列放置皇后。 - 选择在 (1, 2) 放置 Q。(下面for循环中有一个判断,如果不符合条件就不会执行自身函数  所以Q才会直接到第三个)

[ Q . . . ]

[ . . Q . ]

[ . . . . ]

[ . . . . ]

第三层递归 (row = 2): - 尝试在第 2 行的每一列放置皇后。 - 选择在 (2, 1) 放置 Q。

[ Q . . . ]

[ . . Q . ]

[ . Q . . ]

[ . . . . ]

第四层递归 (row = 3): - 尝试在第 3 行的每一列放置皇后。 - 选择在 (3, 3) 放置 Q,找到一个解。

[ Q . . . ]

[ . . Q . ]

[ . Q . . ]

[ . . . Q ]

回溯到第三层,尝试其他列放置皇后: - 尝试在 (2, 2),发现冲突,回溯到第二层。 回溯到第二层,尝试其他列放置皇后: - 尝试在 (1, 3),发现冲突,回溯到第一层。 回溯到第一层,尝试其他列放置皇后: - 尝试在 (0, 1) 放置 Q。

[ . Q . . ]

[ . . . . ]

[ . . . . ]

[ . . . . ] - 接着重复这个过程,直到探索完所有可能。

class Solution {vector<vector<string>> ans;public:void getAns(int n, int row, vector<string>& chessboard) {if (row == n) {ans.push_back(chessboard);return;}for (int col = 0; col < n; col++) {if (isKingdom(row, col, n, chessboard)) {chessboard[row][col] = 'Q';getAns(n, row + 1, chessboard);chessboard[row][col] = '.';}}}bool isKingdom(int row, int col, int n, vector<string>& chessboard) {// 检查列for (int i = 0; i < row; i++) { // 这是一个剪枝if (chessboard[i][col] == 'Q') {return false;}}// 检查 45度角是否有皇后for (int i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) {if (chessboard[i][j] == 'Q') {return false;}}// 检查 135度角是否有皇后for (int i = row - 1, j = col + 1; i >= 0 && j < n; i--, j++) {if (chessboard[i][j] == 'Q') {return false;}}return true;}public:vector<vector<string>> solveNQueens(int n) {vector<string> chessboard(n, string(n, '.'));getAns(n, 0, chessboard);return ans;}
};

 到这里讲解完了,感谢大家观看,给个免费的赞叭!!!

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

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

相关文章

今日股市集体狂飙,下周一呢?

今日&#xff0c;中国人民银行与中国证监会联合印发《关于做好证券、基金、保险公司互换便利&#xff08;SFISF&#xff09;相关工作的通知》&#xff0c;向参与互换便利操作各方明确业务流程、操作要素、交易双方权利义务等内容。目前获准参与互换便利操作的证券、基金公司有2…

链上的羁绊,数据与节点的暗涌心跳

公主请阅 1. 合并两个有序链表1.1 题目说明示例 1示例 2示例 3 1.2 题目分析1.3 代码部分1.4 代码分析 2. 链表的中间节点2.1 题目说明示例 1示例 2 2.2 题目分析2.3 代码部分2.4 代码分析 1. 合并两个有序链表 题目传送门 1.1 题目说明 这个问题要求将两个升序链表合并成一个…

Chinese Fineweb Edu v2即将开源

Chinese Fineweb Edu&#x1f517;&#xff1a;https://opencsg.com/datasets/OpenCSG/chinese-fineweb-edu huggingface&#x1f517;&#xff1a;https://huggingface.co/opencsg

LeetCode 3319. 第 K 大的完美二叉子树的大小

LeetCode 3319. 第 K 大的完美二叉子树的大小 给你一棵 二叉树 的根节点 root 和一个整数k。 返回第 k 大的 完美二叉子树的大小&#xff0c;如果不存在则返回 -1。 完美二叉树 是指所有叶子节点都在同一层级的树&#xff0c;且每个父节点恰有两个子节点。 子树 是指树中的某一…

【4.10】图搜索算法-BFS和DFS解电话号码的字母组合

一、题目 给定一个仅包含数字 2-9 的字符串&#xff0c;返回所有它能表示的字母组合。答案可以按 任意顺序 返回。给出数字到字母的映射如下&#xff08;与电话按键相同&#xff09;。注意 1 不对应任何字母。 示例 1&#xff1a; 输入&#xff1a;digits "23" 输出…

CEEMDAN +组合预测模型(BiLSTM-Attention + ARIMA)

往期精彩内容&#xff1a; 时序预测&#xff1a;LSTM、ARIMA、Holt-Winters、SARIMA模型的分析与比较 全是干货 | 数据集、学习资料、建模资源分享&#xff01; EMD、EEMD、FEEMD、CEEMD、CEEMDAN的区别、原理和Python实现&#xff08;一&#xff09;EMD-CSDN博客 EMD、EEM…

【高阶数据结构】揭开红黑树‘恶魔’的面具:深度解析底层逻辑

高阶数据结构相关知识点可以通过点击以下链接进行学习一起加油&#xff01;二叉搜索树AVL树 大家好&#xff0c;我是店小二&#xff0c;欢迎来到本篇内容&#xff01;今天我们将一起探索红黑树的工作原理及部分功能实现。红黑树的概念相对抽象&#xff0c;但只要我们一步步深入…

flutter assets配置加载本地图片报错

首选列出我在照着网上说的设置assets怎么搞都报错&#xff0c;错误如下&#xff0c;搞的我想骂娘。 flutter: uses-material-design: true assets: - assets/images 后来找到了下面这个教程&#xff0c;才终于解决&#xff0c;就是要在后面加一个"/" 。 flutter这个…

【分布式知识】MapReduce详细介绍

文章目录 MapReduce概述1. MapReduce编程模型Map阶段Reduce阶段 2. Shuffle和Sort阶段3. MapReduce作业的执行流程4. MapReduce的优化和特性5. MapReduce的配置和调优 MapReduce局限性相关文献 MapReduce概述 MapReduce是一个分布式计算框架&#xff0c;它允许用户编写可以在大…

【热门】智慧果园管理系统解决方案

随着科技的进步,原有农业种植方式已经不能满足社会发展的需要,必须对传统的农业进行技术更新和改造。经过多年的实践,人们总结出一种新的种植方法——温室农业,即“用人工设施控制环境因素,使作物获得最适宜的生长条件,从而延长生产季节,获得最佳的产出”。这种农业生产方式…

scala 类的继承

继承的定义 idea实例 语法 重写 重写&#xff1a;在子类中重新定义父类的同名方法 idea实例 多态 多态&#xff1a;传入的对象不同&#xff0c;调用的方法的效果就不同&#xff01; 原理&#xff1a;参数是父类类型 idea实例 构造器

使用开源的 Vue 移动端表单设计器创建表单

FcDesigner Vant 版是一款基于 Vue3.0 的移动端低代码可视化表单设计器工具&#xff0c;通过数据驱动表单渲染。可以通过拖拽的方式快速创建表单&#xff0c;提高开发者对表单的开发效率&#xff0c;节省开发者的时间。 源码下载 | 演示地址 | 帮助文档 本项目采用 Vue3.0 和 …

3D医学影像开发入门<二>:VS2019+Qt5.15.2+VTK9.3.1编译及环境配置

VTK&#xff08;Visualization Toolkit&#xff09;是一个开源的、跨平台的三维可视化开发库&#xff0c;用于处理和可视化三维数据。它提供了一系列算法和工具&#xff0c;用于创建、操作和渲染复杂的三维图形&#xff0c;并支持多种数据表示方式&#xff0c;包括点、线、面、…

Spring Boot知识管理系统:用户体验设计

6系统测试 6.1概念和意义 测试的定义&#xff1a;程序测试是为了发现错误而执行程序的过程。测试(Testing)的任务与目的可以描述为&#xff1a; 目的&#xff1a;发现程序的错误&#xff1b; 任务&#xff1a;通过在计算机上执行程序&#xff0c;暴露程序中潜在的错误。 另一个…

Pycharm下载安装教程(详细步骤)+汉化设置教程

今天讲解的是Pycharm安装教程和配置汉化设置&#xff0c;希望能够帮助到大家。 创作不易&#xff0c;还请各位同学三连点赞&#xff01;&#xff01;收藏&#xff01;&#xff01;转发&#xff01;&#xff01;&#xff01; 对于刚入门学习Python还找不到方向的小伙伴可以试试…

部署私有仓库以及docker web ui应用

官方地址&#xff1a;https://hub.docker.com/_/registry/tags 一、拉取registry私有仓库镜像 docker pull registry:latest 二、运⾏容器 docker run -itd -v /home/dockerdata/registry:/var/lib/registry --name "pri_registry1" --restartalways -p 5000:5000 …

Android取证简介(翻译)

在此文中&#xff0c;我们将探讨 Android 取证、获取 Android 设备的过程、反取证技术以及从 Android 设备映像分析和恢复已删除文件的实际示例。 # 本文中使用的关键术语 采集(Acquisition) &#xff1a; 在数字取证调查期间收集敏感数据 取证健全性(Forensically Soundnes…

【linux】Microsoft Edge 的 Bookmarks 文件存储位置

在 Linux 系统中&#xff0c;Microsoft Edge 的书签&#xff08;Bookmarks&#xff09;文件存储在用户的配置目录下。具体路径通常如下&#xff1a; ~/.config/microsoft-edge/Default/Bookmarks说明&#xff1a; 路径解释&#xff1a; ~ 表示当前用户的主目录。.config 是一个…

pinia学习笔记(1.0)

首先贴出官网地址&#xff1a;开始 | Pinia pinia作为Vue3项目中常用的状态管理工具&#xff0c;正逐渐取代vuex&#xff0c;现从0到1自己搭建pinia仓库。 首先&#xff0c;安装pinia&#xff0c;使用包管理器工具&#xff08;npm,pnpm,yarn,Bun等都可以&#xff09; 安装成…

UE5运行时动态加载场景角色动画任意搭配-相机及运镜(二)

通过《MMD模型及动作一键完美导入UE5》系列文章,我们可以把外部场景、角色、动画资产导入UE5,接下来我们将实现运行时动态加载这些资产,并任意组合搭配。 1、运行时播放相机动画 1、创建1个BlueprintActor,通过这个蓝图动态创建1个LevelSequence,并Play 2、将这个Bluep…