【算法与数据结构】417、LeetCode太平洋大西洋水流问题

文章目录

  • 一、题目
  • 二、解法
  • 三、完整代码

所有的LeetCode题解索引,可以看这篇文章——【算法和数据结构】LeetCode题解。

一、题目

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

二、解法

  思路分析:题目要求雨水既能流向太平洋也能流向大西洋的网格。雨水流向取决于网格的高度。一个比较直接的方式是对每个网格做深度优先搜索,去判断该网格点是否连接太平洋和大西洋,连接的条件就是小于或者等于网格的高度。这样的方法对于当个网格点的复杂度是 O ( m × n ) O(m \times n) O(m×n),一共有 O ( m × n ) O(m \times n) O(m×n)个网格,总的复杂度是 O ( m 2 × n 2 ) O(m^2 \times n^2) O(m2×n2)。这种方法的缺点是没有利用点与点之间的关系,单个网格点的遍历不能再下一次遍历中利用。

  为了能充分利用点与点之间的关系,逆向思维一下,顺着雨水流向逆向遍历。从太平洋边上的节点出发,标记所有能流入太平洋的网格点;同样的方法,从大西洋边上的节点出发,标记所有能流入大西洋的的网格点。然后找到同时有太平洋和大西洋标记的节点输出。

  程序如下

// 417、太平洋大西洋水流问题
class Solution {
private:vector<vector<int>> result;vector<vector<int>> delta_x_y = { {0, -1}, {0, 1}, {-1, 0}, {1, 0} };	// 上下左右四个方向的偏移量void dfs(const vector<vector<int>>& grid, vector<vector<bool>>& visited, int x, int y) {	// 1、递归输入参数visited[x][y] = true;// 3、单层递归逻辑for (int i = 0; i < 4; i++) {int nextx = x + delta_x_y[i][0];int nexty = y + delta_x_y[i][1];//  2、终止条件  逆流而上式的遍历 grid[nextx][nexty] < grid[x][y]if (nextx < 0 || nextx >= grid.size() || nexty < 0 || nexty >= grid[0].size() || visited[nextx][nexty]  || grid[nextx][nexty] < grid[x][y]) continue;	dfs(grid, visited, nextx, nexty);}}
public:vector<vector<int>> pacificAtlantic(vector<vector<int>>& heights) {vector<vector<bool>> pacific = vector<vector<bool>>(heights.size(), vector<bool>(heights[0].size(), false));	// 遍历过的坐标vector<vector<bool>> Atlanti = vector<vector<bool>>(heights.size(), vector<bool>(heights[0].size(), false));for (int i = 0; i < heights[0].size(); i++) {		// 遍历边界行dfs(heights, pacific, 0, i);				// 第一行dfs(heights, Atlanti, heights.size() - 1, i);	// 最后一行						}for (int j = 0; j < heights.size(); j++) {	// 遍历大西洋的网格点dfs(heights, pacific, j, 0);				// 第一列dfs(heights, Atlanti, j, heights[0].size() - 1);	// 最后一列			}for (int i = 0; i < heights.size(); i++) {	// 遍历行 for (int j = 0; j < heights[0].size(); j++) {	// 遍历列if (pacific[i][j] && Atlanti[i][j]) result.push_back({i, j});	// 深度优先搜索,将连接的陆地都标记上true}}return result;}
}; 

复杂度分析:

  • 时间复杂度: O ( m × n ) O(m \times n) O(m×n),其中 m m m n n n分别是网格数组的行数和列数。深度优先搜索的时间复杂度为 O ( m × n ) O(m \times n) O(m×n),主程序当中使用了四个for循环,前两个用来遍历边界,后两个用来遍历太平洋和大西洋的标记数组。前两个for循环的时间复杂度不是 O ( m × ( m × n ) + n × ( m × n ) ) = O ( ( m + n ) × ( m × n ) ) O(m \times (m \times n)+n \times (m \times n)) = O((m+n) \times (m \times n)) O(m×(m×n)+n×(m×n))=O((m+n)×(m×n))。因为我们引入了标记数组,标记过的网格不会多次遍历,实际上的复杂度是两个标记数组遍历的复杂度 O ( 2 × ( m × n ) ) O(2 \times (m \times n)) O(2×(m×n)),后两个循环的复杂度也是 O ( m × n ) O(m \times n) O(m×n)。因此总的时间复杂度为 O ( 3 × m × n ) = O ( m × n ) O(3 \times m \times n) = O(m \times n) O(3×m×n)=O(m×n)
  • 空间复杂度: O ( m × n ) O(m \times n) O(m×n)

三、完整代码

# include <iostream>
# include <vector>
# include <string>
using namespace std;// 417、太平洋大西洋水流问题
class Solution {
private:vector<vector<int>> result;vector<vector<int>> delta_x_y = { {0, -1}, {0, 1}, {-1, 0}, {1, 0} };	// 上下左右四个方向的偏移量void dfs(const vector<vector<int>>& grid, vector<vector<bool>>& visited, int x, int y) {	// 1、递归输入参数visited[x][y] = true;// 3、单层递归逻辑for (int i = 0; i < 4; i++) {int nextx = x + delta_x_y[i][0];int nexty = y + delta_x_y[i][1];//  2、终止条件  逆流而上式的遍历 grid[nextx][nexty] < grid[x][y]if (nextx < 0 || nextx >= grid.size() || nexty < 0 || nexty >= grid[0].size() || visited[nextx][nexty]  || grid[nextx][nexty] < grid[x][y]) continue;	dfs(grid, visited, nextx, nexty);}}
public:vector<vector<int>> pacificAtlantic(vector<vector<int>>& heights) {vector<vector<bool>> pacific = vector<vector<bool>>(heights.size(), vector<bool>(heights[0].size(), false));	// 遍历过的坐标vector<vector<bool>> Atlanti = vector<vector<bool>>(heights.size(), vector<bool>(heights[0].size(), false));for (int i = 0; i < heights[0].size(); i++) {		// 遍历边界行dfs(heights, pacific, 0, i);				// 第一行dfs(heights, Atlanti, heights.size() - 1, i);	// 最后一行						}for (int j = 0; j < heights.size(); j++) {	// 遍历大西洋的网格点dfs(heights, pacific, j, 0);				// 第一列dfs(heights, Atlanti, j, heights[0].size() - 1);	// 最后一列			}for (int i = 0; i < heights.size(); i++) {	// 遍历行 for (int j = 0; j < heights[0].size(); j++) {	// 遍历列if (pacific[i][j] && Atlanti[i][j]) result.push_back({i, j});	// 深度优先搜索,将连接的陆地都标记上true}}return result;}
}; void my_print(vector<vector<int>> result, string message) {cout << message << endl;for (vector<vector<int>>::iterator it = result.begin(); it != result.end(); it++) {for (vector<int>::iterator jt = (*it).begin(); jt != (*it).end(); jt++) {cout << *jt << " ";}cout << endl;}
}int main() {//vector<vector<int>> heights = { { 1, 2, 2, 3, 5},{3, 2, 3, 4, 4},{2, 4, 5, 3, 1},{6, 7, 1, 4, 5},{5, 1, 1, 2, 4} };//vector<vector<int>> heights = { {1} };vector<vector<int>> heights = { {3,3,3,3,3,3}, {3,0,3,3,0,3 }, {3,3,3,3,3,3} };Solution s1;vector<vector<int>> result = s1.pacificAtlantic(heights);my_print(result, "结果:");system("pause");return 0;
}

end

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

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

相关文章

element ui 安装 简易过程 已解决

我之所以将Element归类为Vue.js&#xff0c;其主要原因是Element是&#xff08;饿了么团队&#xff09;基于MVVM框架Vue开源出来的一套前端ui组件。我最爱的就是它的布局容器&#xff01;&#xff01;&#xff01; 下面进入正题&#xff1a; 1、Element的安装 首先你需要创建…

Java设计模式-结构型-适配器模式

Java设计模式-结构型-适配器模式 本文我们简单说下设计模式中的适配器模式。 一、概述 ​ 与电源适配器相似&#xff0c;在适配器模式中引入了一个被称为适配器(Adapter)的包装类&#xff0c;而它所包装的对象称为适配者(Adaptee)&#xff0c;即被适配的类。适配器的实现就是…

基于springboot+vue的桂林旅游景点导游平台(前后端分离)

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…

Spring Security 重点解析

Spring Security 重点解析 文章目录 Spring Security 重点解析1. 简介2. 依赖3. 登录认证3.1 登录校验流程3.2 Spring Security 默认登录的原理3.2.1 Spring Security 完整流程3.2.2 登录逻辑探究 3.3 自定义改动3.3.1 自定义用户密码校验3.3.2 自定义 UserDetails 获取方式 F1…

基于Spring Boot的安康旅游网站的设计与实现,计算机毕业设计(带源码+论文)

源码获取地址&#xff1a; 码呢-一个专注于技术分享的博客平台一个专注于技术分享的博客平台,大家以共同学习,乐于分享,拥抱开源的价值观进行学习交流http://www.xmbiao.cn/resource-details/1760645517548793858

SpringSecurity + OAuth2 详解

SpringSecurity入门到精通 ************************************************************************** SpringSecurity 介绍 **************************************************************************一、入门1.简介与选择2.入门案例-默认的登录和登出接口3.登录经过了…

不做内容引流,你凭什么在互联网上赚钱?

孩子们放寒假了&#xff0c;待在家里不是看电视&#xff0c;就是拿着手机刷视频&#xff0c;脸上是各种欢快和满足。只是一切换到写作业模式&#xff0c;孩子是各种痛苦表情包&#xff0c;家长则是使出浑身解数&#xff0c;上演亲子大战。可见娱乐常常让人愉悦&#xff0c;而学…

鼠标事件和滚轮事件

1. 介绍 QMouseEvent类用来表示一个鼠标事件&#xff0c;当在窗口部件中按下鼠标或者移动鼠标指针时&#xff0c;都会产生鼠标事件。利用QMouseEvent类可以获知鼠标是哪个键按下了&#xff0c;还有鼠标指针的当前位置等信息。通常是重定义部件的鼠标事件处理函数来进行一些自定…

ubuntu使用LLVM官方发布的tar.xz来安装Clang编译器

ubuntu系统上的软件相比CentOS更新还是比较快的&#xff0c;但是还是难免有一些软件更新得不那么快&#xff0c;比如LLVM Clang编译器&#xff0c;目前ubuntu 22.04版本最高还只能安装LLVM 15&#xff0c;而LLVM 18 rc版本都出来了。参见https://github.com/llvm/llvm-project/…

【STM32】Keil RTE使用记录

0 前言 最近因为任务需要&#xff0c;再次开始研究STM32&#xff0c;打算过一遍之前记录的笔记&#xff0c;在创建工程模板时&#xff0c;突然发现一个之前被自己忽略的东西&#xff0c;那就是创建项目时会弹出的Run-Time Environment&#xff0c;抱着好奇的心态去找了一些资料…

防御保护--入侵防御系统IPS

目录 DFI和DPI技术 --- 深度检测技术 入侵防御&#xff08;IPS&#xff09; 签名 入侵防御策略的配置 内容安全&#xff1a;攻击可能只是一个点&#xff0c;防御需要全方面进行 IAE引擎 DFI和DPI技术 --- 深度检测技术 DPI--深度包检测技术--主要针对完整的数据包&#xff0…

冒泡排序法的名字由来,排序步骤是什么,最坏情况下的排序次数如何计算得来的呢?

问题描述&#xff1a;冒泡排序法的名字由来&#xff0c;排序步骤是什么&#xff0c;最坏情况下的排序次数如何计算得来的呢&#xff1f; 问题解答&#xff1a; 冒泡排序法的名字来源于排序过程中较大的元素会像气泡一样逐渐“冒”到序列的顶端&#xff0c;而较小的元素则会逐…

员工离职倾向分析工具

很多公司都担心员工离职&#xff0c;尤其是工龄久的老员工&#xff0c;为什么呢&#xff1f; 很多离职员工带走上家机密&#xff0c;还有的辞职后开公司成为了上家企业的对手公司等等&#xff0c;这类事件非常常见&#xff0c;因此员工离职是一个敏感的话题。 员工离职的原因 …

基于springboot+vue的植物健康系统(前后端分离)

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…

力扣随笔之两数之和 Ⅱ -输入有序数组(中等167)

思路&#xff1a;在递增数组中找出满足相加之和等于目标数 定义左右两个指针&#xff08;下标&#xff09;从数组两边开始遍历&#xff0c;若左右指针所指数字之和大于目标数&#xff0c;则将右指针自减&#xff0c;若左右指针所指数字之和小于目标数&#xff0c;则左指针自加&…

前端(vue)数据存储方案

引言 本需求文档旨在明确前端项目中的数据存储需求&#xff0c;包括数据类型、数据结构、数据交互方式等。它定义了前端项目中需要存储和处理的数据&#xff0c;以及对这些数据进行访问和操作的要求。 功能需求 数据存储按数据类型分为 持久存储、内存存储&#xff08;响应式…

AD24-蛇形走线

一、单端蛇形走线 1、公差参数 2、布线-网络等长调节 3、参数说明 ①手工输入绕线的长度 ②参照个网络的长度绕线 ③按照自身设置的规绕线&#xff08;一般选用) 4、调节 5、最后 二、差分蛇形走线 1、布线-差分对网络等长调节 2、如在选中的时候出现问题&#xff0c;按CtrlD…

Linux学习方法-框架学习法——Linux应用程序编程框架

配套视频学习链接&#xff1a;https://www.bilibili.com/video/BV1HE411w7by?p4&vd_sourced488bc722b90657aaa06a1e8647eddfc 目录 Linux应用程序编程 Linux应用程序编程 Linux文件I/O(input/output) Linux文件I/O(五种I/O模型) Linux多进程 Linux多线程 网络通信(s…

集合、List、Set、Map、Collections、queue、deque

概述 相同类型的数据进行统一管理操作&#xff0c;使用数据结构、链表结构&#xff0c;二叉树 分类&#xff1a;Collection、Map、Iterator 集合框架 List接口 有序的Collection接口&#xff0c;可以对列表中的每一个元u尿素的插入位置进行精确的控制&#xff0c;用户可以根…

Qt事件过滤器

1. 事件过滤器 void QObject::installEventFilter(QObject *filterObj) bool eventFilter(QObject *obj, QEvent *event); filterObj表示事件筛选器对象&#xff0c;它接收发送到此QObject对象&#xff08;安装事件过滤器的部件对象&#xff09;的所有事件。筛选器可以停止事件…