代码随想录训练营第30天|LeetCode 332.重新安排行程、51. N皇后、 37. 解数独、回溯总结

news2024/9/27 8:21:10

参考

代码随想录

题目一:LeetCode 332.重新安排流程

这道题目有几个难点:

  1. 一个行程中,如果航班处理不好容易变成一个圈,成为死循环
  2. 有多种解法,字母序靠前排在前面,让很多同学望而退步,如何该记录映射关系呢 ?
  3. 使用回溯法(也可以说深搜) 的话,那么终止条件是什么呢?
  4. 搜索的过程中,如何遍历一个机场所对应的所有机场。

unordered_map<string,map<string,int>>来记录映射关系,其含义是unordered_map<出发地,map<目的地,航班次数>>

回答上面的问题:

  1. 通过改变航班次数来避免死循环,如果“航班次数”大于零,说明目的地还可以飞,如果如果“航班次数”等于零说明目的地不能飞了,而不用对集合做删除元素或者增加元素的操作。
  2. 在对map<string,int>初始化后,其中的键值对会按照string的字典序排列,所以在遍历targets时也会按照字典序进行,最终得到的结果就是按照字典序排列的。
  3. 如果保存结果的数组result中保存的机场数量等于航班数量加1,则说明所有的航班都遍历过了,可以返回了。
  4. 根据上面给出的映射关系,即unordered_map<出发地,map<目的地,航班次数>>,来遍历每个出发地对应的多个目的地。
  • 递归函数的参数和返回值
    参数:传入航班数量ticketNum,在终止判断的时候会用到;保存结果的数组result.
    返回值:bool类型,如果找到航程就返回true
bool backtracking(int ticketNum,vector<string>& result);
  • 递归终止条件
    当result保存的机场数量等于航班数量加1的时候,说明所有的航班都已经遍历过一次了,此时结束递归。
if(1 + ticketNum == result.size())
	return true;
  • 单层搜索逻辑
    题目中给出,必须从“JFK”出发,因此初始化的时候加"JFK"加入到result中,然后以此为出发地,遍历其所有的目的地,又以这些目的地作为出发地,遍历得到目的地,以此循环,直到找到一个航班。
for (pair<const string, int>& target : targets[result[result.size() - 1]]) {
    if (target.second > 0 ) { // 记录到达机场是否飞过了
        result.push_back(target.first);
        target.second--;
        if (backtracking(ticketNum, result)) return true;
        result.pop_back();
        target.second++;
    }
}

完整的代码实现如下:

class Solution {
private:
// unordered_map<出发机场, map<到达机场, 航班次数>> targets
unordered_map<string, map<string, int>> targets;
bool backtracking(int ticketNum, vector<string>& result) {
    if (result.size() == ticketNum + 1) {
        return true;
    }
    for (pair<const string, int>& target : targets[result[result.size() - 1]]) {
        if (target.second > 0 ) { // 记录到达机场是否飞过了
            result.push_back(target.first);
            target.second--;
            if (backtracking(ticketNum, result)) return true;
            result.pop_back();
            target.second++;
        }
    }
    return false;
}
public:
    vector<string> findItinerary(vector<vector<string>>& tickets) {
        targets.clear();
        vector<string> result;
        for (const vector<string>& vec : tickets) {
            targets[vec[0]][vec[1]]++; // 记录映射关系
        }
        result.push_back("JFK"); // 起始机场
        backtracking(tickets.size(), result);
        return result;
    }
};

题目二:LeetCode 51.N皇后

以3*3为例,搜索过程如下:
在这里插入图片描述

  1. 递归参数和返回值
    参数:n,row(用于记录当前在第几行,类似于之前的startIndex),一个二维数组模拟棋盘上皇后和空格的分布
    返回值:无
void backtracking(int n, int row, vector<string>& chessboard);
  1. 递归终止条件:当遍历到棋盘最底层的时候就可以保存结果并返回了。
if (row == n) {
    result.push_back(chessboard);
    return;
}
  1. 底层搜索逻辑
    递归深度就是row控制棋盘的行,每一层里for循环的col控制棋盘的列,一行一列,确定了放置皇后的位置。每次都是要从新的一行的起始位置开始搜,所以都是从0开始。
for (int col = 0; col < n; col++) {
    if (isValid(row, col, chessboard, n)) { // 验证合法就可以放
        chessboard[row][col] = 'Q'; // 放置皇后
        backtracking(n, row + 1, chessboard);
        chessboard[row][col] = '.'; // 回溯,撤销皇后
    }
}

其中的isValid()函数是判断当前位置的合法性。
完整的代码实现如下:

class Solution {
private:
vector<vector<string>> result;
// n 为输入的棋盘大小
// row 是当前递归到棋盘的第几行了
void backtracking(int n, int row, vector<string>& chessboard) {
    if (row == n) {
        result.push_back(chessboard);
        return;
    }
    for (int col = 0; col < n; col++) {
        if (isValid(row, col, chessboard, n)) { // 验证合法就可以放
            chessboard[row][col] = 'Q'; // 放置皇后
            backtracking(n, row + 1, chessboard);
            chessboard[row][col] = '.'; // 回溯,撤销皇后
        }
    }
}
bool isValid(int row, int col, vector<string>& chessboard, int n) {
    // 检查列
    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) {
        result.clear();
        std::vector<std::string> chessboard(n, std::string(n, '.'));
        backtracking(n, 0, chessboard);
        return result;
    }
};

题目三:LeetCode 37.解数独

  • 递归参数和返回值
bool backtracking(vector<vector<char>>& board);
  • 终止条件
    本题递归不用终止条件,解数独是要遍历整个树形结构寻找可能的叶子节点就立刻返回。
  • 单层搜索逻辑
    需要一个二维的递归(也就是两个for循环嵌套着递归),一个for循环遍历棋盘的行,一个for循环遍历棋盘的列,一行一列确定下来之后,递归遍历这个位置放9个数字的可能性!
bool backtracking(vector<vector<char>>& board) {
    for (int i = 0; i < board.size(); i++) {        // 遍历行
        for (int j = 0; j < board[0].size(); j++) { // 遍历列
            if (board[i][j] != '.') continue;
            for (char k = '1'; k <= '9'; k++) {     // (i, j) 这个位置放k是否合适
                if (isValid(i, j, k, board)) {
                    board[i][j] = k;                // 放置k
                    if (backtracking(board)) return true; // 如果找到合适一组立刻返回
                    board[i][j] = '.';              // 回溯,撤销k
                }
            }
            return false;                           // 9个数都试完了,都不行,那么就返回false
        }
    }
    return true; // 遍历完没有返回false,说明找到了合适棋盘位置了
}

其中的isValid()函数用来判断当前数据分布是否满足条件。
完整的代码实现如下:

class Solution {
private:
bool backtracking(vector<vector<char>>& board) {
    for (int i = 0; i < board.size(); i++) {        // 遍历行
        for (int j = 0; j < board[0].size(); j++) { // 遍历列
            if (board[i][j] == '.') {
                for (char k = '1'; k <= '9'; k++) {     // (i, j) 这个位置放k是否合适
                    if (isValid(i, j, k, board)) {
                        board[i][j] = k;                // 放置k
                        if (backtracking(board)) return true; // 如果找到合适一组立刻返回
                        board[i][j] = '.';              // 回溯,撤销k
                    }
                }
                return false;  // 9个数都试完了,都不行,那么就返回false 
            }                
        }
    }
    return true; // 遍历完没有返回false,说明找到了合适棋盘位置了
}
bool isValid(int row, int col, char val, vector<vector<char>>& board) {
    for (int i = 0; i < 9; i++) { // 判断行里是否重复
        if (board[row][i] == val) {
            return false;
        }
    }
    for (int j = 0; j < 9; j++) { // 判断列里是否重复
        if (board[j][col] == val) {
            return false;
        }
    }
    int startRow = (row / 3) * 3;
    int startCol = (col / 3) * 3;
    for (int i = startRow; i < startRow + 3; i++) { // 判断9方格里是否重复
        for (int j = startCol; j < startCol + 3; j++) {
            if (board[i][j] == val ) {
                return false;
            }
        }
    }
    return true;
}
public:
    void solveSudoku(vector<vector<char>>& board) {
        backtracking(board);
    }
};

回溯总结

什么是回溯

回溯是递归的副产品,只要有递归就会有回溯,所以回溯法也经常和二叉树遍历,深度优先搜索混在一起,因为这两种方式都是用了递归。
回溯法就是暴力搜索,并不是什么高效的算法,最多再剪枝一下。

回溯的思想

回溯算法实际上一个类似枚举的搜索尝试过程,主要是在搜索尝试过程中寻找问题的解,当发现已不满足求解条件时,就“回溯”返回,尝试别的路径。
在回溯中,都会用for循环来横向遍历,递归来纵向遍历,也就是说用递归来控制for循环的次数。
在回溯中会进行剪枝,剪枝通常是根据已经知道的条件缩小for循环的遍历范围。在for循环上做剪枝操作是回溯法剪枝的常见套路!

回溯能解决什么问题

回溯算法能解决如下问题:

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

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

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

相关文章

没有项目管理经验,可以参加PMP考试吗?

咱们先来了解一下PMP&#xff0c;PMP认证是一项针对项目管理的资格认证&#xff0c;属于管理学中的经济/项目管理&#xff0c;也是目前职业资格认证中含金量较高的&#xff0c;堪比MBA、MPA。 许多大型私企和外企在招聘项目管理者和项目组成员的时候都优先考虑持有PMP认证的人…

【问题】Nginx部署vue项目进行跳转二级路由报404无法找到目标页面问题和Nginx部署vue项目访问不了接口

Nginx部署vue项目进行跳转二级路由报404无法找到目标页面问题和Nginx部署vue项目访问不了接口 文章目录Nginx部署vue项目进行跳转二级路由报404无法找到目标页面问题和Nginx部署vue项目访问不了接口Nginx部署vue项目进行跳转二级路由报404无法找到目标页面问题**问题** &#x…

社区垃圾分类督导AI盒子应用的痛点难点分析

载止于2022年底&#xff0c;我司A社区垃圾分类督导AI视频分析盒子已经在华东(上海、杭州、无锡等地&#xff09;&#xff0c;华南地区&#xff08;深圳等地&#xff09;大量上线&#xff0c;本人负责垃圾分类算法AI盒子的开发历时5年之久&#xff0c;从多年试点到现在规模上线使…

react源码分析:组件的创建和更新

这一章节就来讲讲ReactDOM.render()方法的内部实现与流程吧。 因为初始化的源码文件部分所涵盖的内容很多&#xff0c;包括创建渲染、更新渲染、Fiber树的创建与diff&#xff0c;element的创建与插入&#xff0c;还包括一些优化算法&#xff0c;所以我就整个的React执行流程画了…

算法入门 | 二叉树的递归遍历、递归创建系列(递归)

目录 1. 二叉树的遍历规则 2. 二叉树的结构体设计 【leftchild data rightchild】 3. 二叉树的递归先序、中序、后序遍历 4. 利用已知字符串&#xff08;二叉树的先序序列&#xff09;递归创建一棵二叉树 &#xff08;1&#xff09;购买节点函数 &#xff08;2&#xff…

【附源码】计算机毕业设计JAVA移动学习网站

【附源码】计算机毕业设计JAVA移动学习网站 目运行 环境项配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; JAVA mybati…

阻止网络钓鱼诈骗的技巧

根据 Verizon 的2022 年数据泄露调查报告&#xff0c;25% 的数据泄露始终涉及网络钓鱼。 这是怎么发生的&#xff1f;参与网络钓鱼的欺诈者往往是一些掌握发文技巧的内容作者。他们知道如何创造一种紧迫感&#xff0c;让您点击通知并阅读消息。 很多用户落入了他们的陷阱&…

录屏软件哪个好?比较好用的录屏软件,这4款值得一试!

​现在很多人都会使用录屏软件&#xff0c;有些用来录制游戏里的精彩操作&#xff0c;有些用来录制线上的教学课程&#xff0c;有些用来录制在线视频会议。如今录屏软件种类繁多。选择一个好的录屏软件十分重要。录屏软件哪个好&#xff1f;比较好用的录屏软件有哪些&#xff1…

Zebec开启多链布局,流支付生态持续扩张

随着 Do Kwon 的Terra 以及 Sam Bankman-Fried 的 FTX&#xff0c;这两个加密行业的“庞大帝国”轰然倒塌后&#xff0c;Terra生态毁于一旦&#xff0c;而辉煌一时的Solana生态也失去了“靠山”&#xff0c;尤其是在Solana屡次宕机、在FTX危机时增发SOL代币后&#xff0c;进一步…

骨传导耳机会损伤大脑吗?一分钟详细了解骨传导耳机

骨传导耳机会损伤大脑吗&#xff1f;这个问题一直都有很多人在问&#xff0c;相对传统入耳式耳机来说&#xff0c;骨传导耳机更能保护我们的听力与大脑&#xff0c;骨传导耳机的工作原理跟传统耳机不一样&#xff0c;它不会损伤到大脑&#xff0c;下面我来跟大家说一下骨传导耳…

Python: 10大Web框架简介

文章目录简介一、Web 框架三大分类**1. 全栈框架****2.微框架****3.异步框架**二、Python Web 框架的优点三、十大 Python Web 开发框架1.Django2. Flask3.CherryPy4.Pyramid5. Grok6.Turbogears7.Zope38. Bottle9.Web2py10. Tornado小结简介 在这篇文章中了解一些可供您使用的…

dolphinscheduler-data-quality-3.1.0 部署

前提条件 dophinscheduler-3.1.0 安装 standalone-server 模式&#xff0c;参考 https://blog.csdn.net/windydreams/article/details/127678233 编译数据质量源码 为了保障后期正常运行&#xff0c;简化配置&#xff0c;可以进行以下配置 1&#xff09;添加资源文件src/mai…

疫情之下,企业如何才能高效的进行异地协同办公?

随着经济社会的飞速发展再加上现在疫情反反复复的出现&#xff0c;很多公司的业务不再受地域的限制&#xff0c;所以出差就成了很多职场人士的家常便饭&#xff0c;而这一现象也加剧了异地办公模式的兴起&#xff0c;因为即便身处异地&#xff0c;也需要及时向领导汇报工作进度…

防爆定位信标与防爆定位基站有什么区别?

防爆定位信标与防爆定位基站都是组成人员定位系统的硬件设备。一套完整的人员定位系统由硬件设施和软件系统组成&#xff0c;其中硬件设施包括人员定位卡、防爆定位信标和防爆定位基站。 在大数据、信息化时代&#xff0c;基于蓝牙LoRa定位技术的融合定位系统&#xff0c;让我们…

2008-2020年全国各省劳动生产率

2008-2020年全国各省劳动生产率 1、包括&#xff1a;全国31省 2、来源&#xff1a;国J统计局 3、指标包括&#xff1a; 人均受教育年限、劳动生产率、6岁及6岁以上人口数(人口抽样调查)(人)、6岁及6岁以上初中人口数(人口抽样调查)(人)、 6岁及6岁以上大专及以上人口数(人…

机器学习分类方法

1、支持向量机 1.1支持向量机简介&#xff1a; 支持向量机&#xff08;support vector machines, SVM&#xff09;是一种二分类模型&#xff0c;它的基本模型是定义在特征空间上的间隔最大的线性分类器&#xff0c;间隔最大使它有别于感知机&#xff1b;SVM还包括核技巧&…

【教学类-18-02】20221124《蒙德里安“红黄蓝黑格子画”-A4竖版》(大班)

效果展示&#xff1a; 单页效果 多页效果 预设效果 背景需求&#xff1a; 2022年11月23日&#xff0c;作为艺术特色幼儿园&#xff0c;蒙德里安风格装饰在我们幼儿园的环境中。 蒙德里安是几何抽象画派的先驱&#xff0c;以几何图形为绘画的基本元素&#xff0c;与德士堡等创…

Python毕业设计选题推荐

同学们好&#xff0c;这里是海浪学长的毕设系列文章&#xff01; 对毕设有任何疑问都可以问学长哦! 大四是整个大学期间最忙碌的时光,一边要忙着准备考研,考公,考教资或者实习为毕业后面临的就业升学做准备,一边要为毕业设计耗费大量精力。近几年各个学校要求的毕设项目越来越…

释放数据生产力,数据治理要“即时”

近年来&#xff0c;数据成为核心生产要素之后&#xff0c;人们总是期待充分释放数据生产力。但知易行难&#xff0c;如何释放数据生产力&#xff0c;大部分企业却莫衷一是、无所适从。 尤其是针对文档等非结构化数据&#xff0c;工程设计、生物医药、智能制造、金融、教育等行…

关于地方美食的HTML网页设计——地方美食介绍网站 HTML顺德美食介绍 html网页制作代码大全

&#x1f380; 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业…