搜索算法(五) DFS BFS 练习题

news2024/11/24 11:50:29

练习题

1.
力扣https://leetcode.cn/problems/surrounded-regions/这题和417类似,都是从边界朝内部搜索,417用的是DFS,这里为了练习,就用BFS。

首先从四条边界得到‘O’的坐标,加入队列。接着一层一层搜索,将所有相邻且为‘O'元素坐标加入队列,并且标记为已访问。

搜索结束后,遍历整个数组,将所有未访问的'O'标记为'X',因为所有边界可达的'O'都已被标记为访问过。

class Solution {
public:
    void solve(vector<vector<char>>& board) {
        int m = board.size();
        int n = board[0].size();
        queue<pair<int,int>> q;
        vector<vector<bool>> visit(m,vector<bool>(n,false));
        for(int i=0;i<n;i++){
            
            if(board[0][i]=='O'){
                q.push({0,i});
                visit[0][i] = true;
            }
            if(board[m-1][i]=='O'){
                q.push({m-1,i});
                visit[m-1][i] = true;
            }
        }
        for(int i=1;i<m-1;i++){
            
            if(board[i][0]=='O'){
                q.push({i,0});
                visit[i][0] = true;
            }
            if(board[i][n-1]=='O'){
                q.push({i,n-1});
                visit[i][n-1] = true;
            }
        }
        vector<int> path = {-1,0,1,0,-1};
        while(!q.empty()){
            int k = q.size();
          
            for(int i=0;i<k;i++){
               
                auto [a,b] = q.front();
                q.pop();
                for(int j=0;j<4;j++){
                    int x = a + path[j];
                    int y = b + path[j+1];
                    if(x>=0 && x<m && y>=0 && y<n && 
                        board[x][y] =='O' && visit[x][y]==false
                    ){
                        
                        q.push({x,y});
                        visit[x][y] = true;
                    }
                }
            }
        }
        for(int i=0;i<m;i++){
            for(int j=0;j<n;j++){
                if(board[i][j]=='O'&& visit[i][j]==false){
                    board[i][j] = 'X';
                }
            }
        }

        


    }
};

2.力扣https://leetcode.cn/problems/binary-tree-paths/这题是一道典型的DFS,题目不难,但注意不要写成引用传递了。

不然就会像我一开始那样,string插入弹出写了半天,老是不对。(因为确定不了一个数字到底是几位char)

仔细一看,写成值传递,这样函数结束时,path上新增的内容都会自然消除。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    vector<string> binaryTreePaths(TreeNode* root) {
        vector<string> res;
        dfs(root,"",res);
        return res;
    }

    void dfs(TreeNode* root, string path, vector<string>& res){
       if(root){
           path += to_string(root->val);
           if(!root->left && !root->right){
               res.push_back(path);
           }else{
               path += "->";
               dfs(root->left,path,res);
               dfs(root->right,path,res);
               
           }
       }
    }


};

3.力扣https://leetcode.cn/problems/permutations-ii/

这题是典型的DFS,考虑到重复数字直接DFS,会产生重复的排列,有两种解决方法。

一是用set存储排列,自动去除了重复的排列。

二是跳过与前一个数字重复的数字(且前一个数字是未访问的)。

这里采用第二种方法:

class Solution {
public:
    vector<vector<int>> permuteUnique(vector<int>& nums) {
        int n = nums.size();
        vector<int> path;
        vector<vector<int>> res;
        vector<bool> visit(n,false);
        sort(nums.begin(), nums.end());
        
        dfs(nums,path,res,visit);
            
        return res;
    }

    void dfs(vector<int>& nums, vector<int> path, vector<vector<int>>& res, vector<bool> visit){
        if(path.size()==nums.size()){
            res.push_back(path);
        }else{
            int n = nums.size();
            for(int i=0;i<n;i++){
                if(visit[i]==false){
                    if(i==0 || (nums[i]!=nums[i-1]) || visit[i-1]==true){
                        path.push_back(nums[i]);
                        visit[i] = true;
                        dfs(nums,path,res,visit);
                        visit[i] = false;
                        path.pop_back();
                    }
                }
            }
        }
    }
};

4.力扣https://leetcode.cn/problems/sudoku-solver/

解数独的关键在于记录每行每列每个3x3方块的数字,然后对空格处依次遍历可能的数字。

先预处理矩阵,然后DFS,需要注意的是DFS的递归方法中,最后找到目标解法后,要在每一层递归直接return,不然会继续遍历可能的数字。

class Solution {
public:
    void solveSudoku(vector<vector<char>>& board) {
        memset(row,false,sizeof(row));
        memset(col,false,sizeof(col));
        memset(cube,false,sizeof(cube));


        for(int i=0;i<9;i++){
            for(int j=0;j<9;j++){
                if(board[i][j]=='.'){
                    path.push_back({i,j});
                }else{
                    int m = board[i][j] - '0';
                    row[i][m] = col[j][m] = cube[i/3][j/3][m] = true;
                }
            }
        }

        dfs(board,0);
    }

    bool dfs(vector<vector<char>>& board, int x){
        if(x>=path.size()){
            return true;
        }
        auto [a,b] = path[x];
        for(int i=1;i<=9;i++){
            if(!row[a][i] && !col[b][i] && !cube[a/3][b/3][i]){
                row[a][i] = col[b][i] = cube[a/3][b/3][i] = true;
                board[a][b] = '0' + i;
                if(dfs(board,x+1))
                    return true;
                row[a][i] = col[b][i] = cube[a/3][b/3][i] = false;
            }
        }
        return false;
    }

private:
    bool row[9][10];
    bool col[9][10];
    bool cube[3][3][10];
    vector<pair<int,int>> path;
};

5.力扣icon-default.png?t=N5F7https://leetcode.cn/problems/minimum-height-trees/这题挺绕的,记忆化DFS过不了所有的答案,必须要用拓朴排序。

虽然我不懂 这种解法为啥要叫拓扑排序,但看题解都这么说那就是了吧。

拓朴排序解这道题就绕开了搜索的问题。

要找高度最小的根节点,这个根节点应该出现在两个相距最远的叶子节点的中间位置。不然的话,其中一个子树的高度就会很高。

举个例子,两个叶子节点相距11,如果我选最中间的节点作为根节点,那么树高度为6.

如果随便选了叶子节点相邻的节点作为根节点,那么树高度为9。

有了这个思想之后,怎么实现代码呢?

这个题解链接里的这两张图很好地说明了方法:

 

目标是寻找距离最远的两个叶子节点的中间节点,我们无法立刻知道哪两个叶子节点相距最远。

所以每次都删除掉最外围的叶子节点(也就是入度为1的节点),删掉叶子节点之后,与它们相连的入度为2的节点就会变成新的叶子节点,这样新一轮继续删除叶子节点,更新与它们相连的节点的度数。

这里有些类似层次遍历,每一次删除最外层节点,当删除到只剩下两个或一个节点时,可以认为它们是最中间的节点,作为答案返回。 

看上图还是挺生动形象的,从相距最远的节点,一层一层剥开,最后找到中心节点。

代码:

class Solution {
public:
    vector<int> findMinHeightTrees(int n, vector<vector<int>>& edges) {
       if(n==1) return vector<int>{0};
       vector<int> degree(n,0);
       vector<vector<int>> connect(n);
       for(auto e:edges){
        connect[e[0]].emplace_back(e[1]);
        connect[e[1]].emplace_back(e[0]);
        degree[e[0]]++;
        degree[e[1]]++;
       }
        
       queue<int> q;
       for(int i=0;i<n;i++){
           if(degree[i]==1){
               q.push(i);
           }
       }
       while(n>2){
           int m = q.size();
           n -= m;
          
           for(int i=0;i<m;i++){
               int t = q.front();
               q.pop();
               for(int c:connect[t]){
                   degree[c]--;
                   if(degree[c]==1){
                       q.push(c);
                   }
               }
           }
       }
      
       vector<int> res;
       while(q.size()>0){
           res.push_back(q.front());
           q.pop();
       }
       return res;


    }




   
};

Reference:

力扣

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

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

相关文章

11个AI绘画软件大全,赶紧收藏

随着人工智能技术的不断发展&#xff0c;越来越多的AI绘画软件应运而生。AI绘画软件利用人工智能技术&#xff0c;通过计算机自动生成或辅助生成艺术作品。 AI绘画软件通常集深度学习、计算机视觉、自然语言处理等技术于一体&#xff0c;可以模拟人类的创作过程&#xff0c;生…

带你详细了解Redis事务锁机制-加实列演示-加连接池-包括解决遗留问题-下

Redis_事务_锁机制_秒杀 连接池技术 连接池介绍 1、节省每次连接redis 服务带来的消耗&#xff0c;把连接好的实例反复利用。 2、链接池参数 MaxTotal&#xff1a;控制一个pool 可分配多少个jedis 实例&#xff0c;通过pool.getResource()来获取&#xff1b;如果赋值为-1&…

.NetCore gRpc 客户端与服务端的单工通信Demo

文章目录 .NetCore gRpc 客户端与服务端的单工通信Demo服务端方式一方式二 客户端proto协议文件syntax "proto3";import "google/protobuf/empty.proto";serviceproto3与.netCore 的类型对应日期和时间可为 null 的类型字节小数为 Protobuf 创建自定义 de…

<Linux开发>驱动开发 -Linux MISC 驱动

&#xff1c;Linux开发&#xff1e;驱动开发 -Linux MISC 驱动 交叉编译环境搭建&#xff1a; &#xff1c;Linux开发&#xff1e; linux开发工具-之-交叉编译环境搭建 uboot移植可参考以下&#xff1a; &#xff1c;Linux开发&#xff1e; -之-系统移植 uboot移植过程详细记…

软考高级系统架构设计师(二) 基础知识之计算机组成与系统结构2

目录 总线 ​CISC与RISC 流水线技术 总线 练习题&#xff1a; CISC与RISC RISC(精简指令集计算机)和CISC(复杂指令集计算机)是当前CPU的两种架构. RISC与CICS的比较 1.RISC比CICS更能提高计算机运算速度&#xff1b;RISC寄存器多&#xff0c;就可以减少访存次数&#xff0c;…

生产环境Java应用服务内存泄漏分析与解决

有个生产环境CRM业务应用服务&#xff0c;情况有些奇怪&#xff0c;监控数据显示内存异常。内存使用率99.%多。通过生产监控看板发现&#xff0c;CRM内存超配或内存泄漏的现象&#xff0c;下面分析一下这个问题过程记录。 1、服务器硬件配置部署情况 生产服务器采用阿里云ECS…

【命令参数】MSBuild - 环境配置及常用命令参数

目录 环境配置 基本语法 参数指令 对各类程序的命令参数的掌握是软件工程师必修课之一&#xff0c;它是通往自动化、高效化开发测试的必经之路。对于MSBuild&#xff0c;我们可以借助它以一种轻量级的形式去完成对于项目又或解决方案的生成&#xff0c;而避开使用繁大的IDE进…

Linux系统之部署Etherpad文档编辑器

Linux系统之部署Etherpad文档编辑器 一、Etherpad介绍1.Etherpad简介2.Etherpad特点 二、本地环境介绍2.1 本地环境规划2.2 本次实践介绍 三、检查本地环境3.1 检查本地操作系统版本3.2 检查系统内核版本3.3 检查系统是否安装Node.js 四、部署Node.js 环境4.1 下载Node.js安装包…

【吴恩达老师《机器学习》】课后习题3之【逻辑回归解决多分类】与【神经网络】笔记(代码注释详细)

本次习题所用到的数据&#xff0c;#数据集&#xff1a;ex3data1.mat&#xff0c;参数&#xff1a;ex3weights.mat。在文章开头&#xff0c;下载即可&#xff01; 逻辑回归解决多分类问题 二分类VS多分类 在机器学习中&#xff0c;分类是一种监督学习任务&#xff0c;其中我们…

从机缘到成就

机缘 在这1825天的创作之旅中&#xff0c;我收获了许多宝贵的机遇和经验。起初&#xff0c;我只是一个对技术有着浓厚兴趣的普通人&#xff0c;遇到了一个在eclipse导入工程后出现中文乱码的问题。而我决定将这个问题记录下来&#xff0c;并分享给其他可能遇到相同困扰的人们。…

数据库系统概述——第三章 关系数据库标准语言SQL(知识点复习+练习题)

&#x1f31f;博主&#xff1a;命运之光 &#x1f984;专栏&#xff1a;离散数学考前复习&#xff08;知识点题&#xff09; &#x1f353;专栏&#xff1a;概率论期末速成&#xff08;一套卷&#xff09; &#x1f433;专栏&#xff1a;数字电路考前复习 &#x1f99a;专栏&am…

Linux基础内容(23)—— 信号补充与多线程交接知识

Linux基础内容&#xff08;22&#xff09;—— 信号_哈里沃克的博客-CSDN博客https://blog.csdn.net/m0_63488627/article/details/130835485 目录 1.可重入函数 1.情况假设 2.volatile 3.SIGCHLD信号 1.SIGCHLD介绍 2.信号的确认 3.wait的处理 1.可重入函数 1.情况假设…

插件 - 通过SPI方式实现插件管理

文章目录 SPI概念基本原理使用步骤优点缺点Code真实使用场景案例JDBC(Java Database Connectivity)Servlet API日志框架SPI概念 SPI(Service Provider Interface)是Java提供的一种服务扩展机制,它允许应用程序在运行时动态加载和发现提供者(Providers),并与它们进行交…

Proteus仿真之UART通信(点亮LED灯)

1.UART通信简介&#xff1a;通用异步收发传输器UART(Universal Asynchronous Receiver/Transmitter)是负责处理数据总线和串口之间的串/并通信的设备。UART通信规定了数据帧的格式&#xff1a;起始位、数据位、校验位、停止位等。UART异步通信只需要通信双方设置好数据帧的格式…

房屋装修选择自装,如何寻找水电工人,比价并施工(水电阶段)

环境&#xff1a; 地点&#xff1a;杭州 装修类型&#xff1a;自装 面积&#xff1a;建面135平方 进度&#xff1a;水电阶段 问题描述&#xff1a; 房屋装修选择自装&#xff0c;如何寻找水电工人&#xff0c;比价并施工 解决方案&#xff1a; 一、了解水电相关知识 水…

Python3+RIDE+RobotFramework自动化测试框架搭建

Python2.7已于2020年1月1日开始停用&#xff0c;之前RF做自动化都是基于Python2的版本。 没办法&#xff0c;跟随时代的脚步&#xff0c;我们也不得不升级以应用新的控件与功能。 升级麻烦&#xff0c;直接全新安装。 一、Python安装 最新版Python下载地址&#xff1a;http…

Qt连接Access数据库

Qt自带有QODBC驱动&#xff08;封装了ODBC驱动接口&#xff09;&#xff0c;通过windows平台上提供的ODBC驱动访问支持ODBC的数据库&#xff0c;如Ms Access、SQL Server等 (Windows XP 自带有Access和SQL Server的ODBC Driver)。我们就用QODBC对Access数据库进行访问。 Acces…

别再瞎搞了,耳朵都竖起来听我说,新手小白开发应该如何选择最合适你的JetBrains IDE版本类型和版本号! 今天一次性给你说清楚!

&#x1f680; 个人主页 极客小俊 ✍&#x1f3fb; 作者简介&#xff1a;web开发者、设计师、技术分享博主 &#x1f40b; 希望大家多多支持一下, 我们一起进步&#xff01;&#x1f604; &#x1f3c5; 如果文章对你有帮助的话&#xff0c;欢迎评论 &#x1f4ac;点赞&#x1…

windows环境下搭建redis集群

下面记录一下windows10环境下搭建redis3主3从集群&#xff0c;将过程分享出来&#xff0c;仅供学习研究使用。 1、redis集群 Redis集群关键点就是去掉中心化(与哨兵模式的区别)&#xff0c;当主机宕机&#xff0c;从节点回自动升级为主节点&#xff0c;具体请参考官网或相关大…

机器学习——KNN算法(手动代码,含泪)

徒手实现代码的过程&#xff0c;真是含泪和心酸&#xff0c;浪费了生命中的三天&#xff0c;以及工作中的划水一小时 终于滤清思路后&#xff0c;自己实现了KNN 都说KNN是最基础&#xff0c;最简单的分类器 放屁&#xff01;骗纸&#xff01;&#xff01;&#xff01;它的想法是…