当前位置: 首页 > news >正文

25寒假算法刷题 | Day1 | LeetCode 240. 搜索二维矩阵 II,148. 排序链表

目录

  • 240. 搜索二维矩阵 II
    • 题目描述
    • 题解
  • 148. 排序链表
    • 题目描述
    • 题解

240. 搜索二维矩阵 II

点此跳转题目链接

题目描述

编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target 。该矩阵具有以下特性:

  • 每行的元素从左到右升序排列。
  • 每列的元素从上到下升序排列。

示例 1:

在这里插入图片描述

输入:matrix = [[1,4,7,11,15],[2,5,8,12,19],[3,6,9,16,22],[10,13,14,17,24],[18,21,23,26,30]], target = 5
输出:true

示例 2:

在这里插入图片描述

输入:matrix = [[1,4,7,11,15],[2,5,8,12,19],[3,6,9,16,22],[10,13,14,17,24],[18,21,23,26,30]], target = 20
输出:false

提示:

  • m == matrix.length
  • n == matrix[i].length
  • 1 <= n, m <= 300
  • -109 <= matrix[i][j] <= 109
  • 每行的所有元素从左到右升序排列
  • 每列的所有元素从上到下升序排列
  • -109 <= target <= 109

题解

暴力算法直接遍历整个矩阵,时间复杂度为 O ( m n ) O(mn) O(mn) m 、 n m、n mn 分别为矩阵的行、列数。

由于题中矩阵在行和列上的元素都是升序的,所以想到可以从上到下逐行利用二分查找解决:

class Solution {
public:int binarySearch(const vector<int>& arr, int target) {int left = 0;int right = arr.size() - 1;while (left <= right) {int mid = left + (right - left) / 2;if (arr[mid] < target) {left = mid + 1;} else if (arr[mid] > target) {right = mid - 1;} else {return mid;}}return -1;}bool searchMatrix(vector<vector<int>>& matrix, int target) {if (matrix.empty()) {return false;}// 逐行使用二分法查找targetfor (const vector<int>& line : matrix) {if (binarySearch(line, target) != -1) {return true;}}return false;}
};

行内 n n n 个元素做二分查找的时间复杂度为 O ( l o g n ) O(logn) O(logn) ,共 m m m 行,故时间复杂度为 O ( m l o g n ) O(mlogn) O(mlogn)

不过上面两种方法似乎都过于直白简单了,考虑到这个题目带的是“中等”tag,肯定还有更高效的算法:

🔗 以下内容来自 LeetCode官方题解

我们可以从矩阵 matrix 的右上角 (0,n−1) 进行搜索。在每一步的搜索过程中,如果我们位于位置 (x,y) ,那么我们希望在以 matrix 的左下角为左下角、以 (x,y) 为右上角的矩阵中进行搜索,即行的范围为 [x,m−1] ,列的范围为 [0,y]

  • 如果 matrix[x,y]=target ,说明搜索完成
  • 如果 matrix[x,y]>target ,由于每一列的元素都是升序排列的,那么在当前的搜索矩阵中,所有位于第 y 列的元素都是严格大于 target 的,因此我们可以将它们全部忽略,即将 y 减少 1
  • 如果 matrix[x,y]<target ,由于每一行的元素都是升序排列的,那么在当前的搜索矩阵中,所有位于第 x 行的元素都是严格小于 target 的,因此我们可以将它们全部忽略,即将 x 增加 1。

在搜索的过程中,如果我们超出了矩阵的边界,那么说明矩阵中不存在 target 。代码实现如下:

class Solution {
public:bool searchMatrix(vector<vector<int>>& matrix, int target) {int x = 0;int y = matrix[0].size() - 1;while (x < matrix.size() && y >= 0) {if (matrix[x][y] < target) {x++;} else if (matrix[x][y] > target) {y--;} else {return true;}}return false;}
};

时间复杂度: O ( m + n ) O(m+n) O(m+n) 。在搜索的过程中,如果我们没有找到 target ,那么我们要么将 y 减少 1,要么将 x 增加 1。由于 (x,y) 的初始值分别为 (0,n−1) ,因此 y 最多能被减少 n 次, x 最多能被增加 m 次,总搜索次数为 m+n 。在这之后, xy 就会超出矩阵的边界。


148. 排序链表

点此跳转题目链接

题目描述

给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表

示例 1:

在这里插入图片描述

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

示例 2:

在这里插入图片描述

输入:head = [-1,5,3,4,0]
输出:[-1,0,3,4,5]

示例 3:

输入:head = []
输出:[]

提示:

  • 链表中节点的数目在范围 [0, 5 * 104]
  • -105 <= Node.val <= 105

进阶: 你可以在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序吗?

题解

暴力解法无需多言,遍历一遍链表获取全部元素、排序后重新整一个新链表即可:

struct ListNode
{int val;ListNode *next;ListNode() : val(0), next(nullptr) {}ListNode(int x) : val(x), next(nullptr) {}ListNode(int x, ListNode *next) : val(x), next(next) {}
};class Solution {
public:ListNode* sortList(ListNode* head) {vector<int> elements;while (head){elements.push_back(head->val);head = head->next;}sort(elements.begin(), elements.end());ListNode *dummyHead = new ListNode();ListNode *cur = dummyHead;for (int element : elements) {cur->next = new ListNode(element);cur = cur->next;}return dummyHead->next;}
};

上述算法时间复杂度为 sort() O ( n log ⁡ n ) O(n\log{n}) O(nlogn) ,空间复杂度为 O ( n ) O(n) O(n) ——因为新建了一个链表。 直接看看进阶要求:时间复杂度为 O ( n log ⁡ n ) O(n\log{n}) O(nlogn) ,空间复杂度为常数级。

考虑算法题中常用的高效排序算法——归并排序,有:

class Solution {
public:ListNode *merge(ListNode *L, ListNode *R) {ListNode dummyHead;ListNode *cur = &dummyHead;while (L && R) {if (L->val < R->val) {cur->next = L;L = L->next;} else {cur->next = R;R = R->next;}cur = cur->next;}cur->next = L ? L : R;return dummyHead.next;}ListNode *sortList(ListNode *head, ListNode *tail) {if (!head || head == tail) return head;// 快慢指针找到链表中点ListNode *slow = head, *fast = head;while (fast != tail && fast->next != tail) {slow = slow->next;fast = fast->next->next;}ListNode *mid = slow->next;slow->next = nullptr;  // 断开链表return merge(sortList(head, slow), sortList(mid, tail));}ListNode *sortList(ListNode *head) { return sortList(head, nullptr); }
};

上述算法时间复杂度为 O ( n log ⁡ n ) O(n\log{n}) O(nlogn) ,即归并排序的时间复杂度。空间复杂度取决于递归调用的栈空间,为 O ( log ⁡ n ) O(\log{n}) O(logn) ,还是没到最佳的常数级别。为此,需要采用“自底向上”的归并排序实现 O ( 1 ) O(1) O(1) 的空间复杂度:

🔗 以下内容参考 LeetCode官方题解

首先求得链表的长度 length ,然后将链表拆分成子链表进行合并。具体做法如下:

  • subLength 表示每次需要排序的子链表的长度,初始时 subLength=1
  • 每次将链表拆分成若干个长度为 subLength 的子链表(最后一个子链表的长度可以小于 subLength ),按照每两个子链表一组进行合并,合并后即可得到若干个长度为 subLength×2 的有序子链表(最后一个子链表的长度可以小于 subLength×2 )。合并两个子链表仍然使用之前用过的归并算法。
  • subLength 的值加倍,重复第 2 步,对更长的有序子链表进行合并操作,直到有序子链表的长度大于或等于 length ,整个链表排序完毕。

通过数学归纳法易证最后得到的链表是有序的(每次合并用到的子链表是有序的,合并后的也是有序的)。

class Solution {
public:ListNode *merge(ListNode *L, ListNode *R) {ListNode dummyHead;ListNode *cur = &dummyHead;while (L && R) {if (L->val < R->val) {cur->next = L;L = L->next;} else {cur->next = R;R = R->next;}cur = cur->next;}cur->next = L ? L : R;return dummyHead.next;}ListNode *sortList(ListNode *head) {if (!head) {return nullptr;}// 获取链表长度int length = 0;ListNode *cur = head;while (cur != nullptr) {length++;cur = cur->next;}// 自底向上,两两合并长度为subLength的子链表ListNode *dummyHead = new ListNode(0, head);for (int subLength = 1; subLength < length; subLength <<= 1) {ListNode *prev = dummyHead;cur = prev->next;while (cur != nullptr) {// 获取第一个子链表ListNode *head1 = cur;for (int i = 1; i < subLength && cur->next != nullptr; ++i) {cur = cur->next;}// 获取第二个子链表ListNode *head2 = cur->next;cur->next = nullptr;  // 断开第一个子链表结尾cur = head2;for (int i = 1; i < subLength && cur && cur->next; ++i) {cur = cur->next;}// 预存第三个子链表(即下一轮的第一个子链表)的头节点// 即第二个子链表结尾节点的next节点ListNode *nextHead = nullptr;if (cur != nullptr) {nextHead = cur->next;cur->next = nullptr;  // 断开第二个子链表结尾}// 合并第一、二个子链表ListNode *merged = merge(head1, head2);// 更新prev、cur指针prev->next = merged;while (prev->next != nullptr) {prev = prev->next;}cur = nextHead;}}return dummyHead->next;}
};

该算法时间复杂度为 O ( n log ⁡ n ) O(n \log{n}) O(nlogn) ,空间复杂度为 O ( 1 ) O(1) O(1)

相关文章:

25寒假算法刷题 | Day1 | LeetCode 240. 搜索二维矩阵 II,148. 排序链表

目录 240. 搜索二维矩阵 II题目描述题解 148. 排序链表题目描述题解 240. 搜索二维矩阵 II 点此跳转题目链接 题目描述 编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target 。该矩阵具有以下特性&#xff1a; 每行的元素从左到右升序排列。每列的元素从上到…...

MQTT知识

MQTT协议 MQTT 是一种基于发布/订阅模式的轻量级消息传输协议&#xff0c;专门针对低带宽和不稳定网络环境的物联网应用而设计&#xff0c;可以用极少的代码为联网设备提供实时可靠的消息服务。MQTT 协议广泛应用于物联网、移动互联网、智能硬件、车联网、智慧城市、远程医疗、…...

【机器学习与数据挖掘实战】案例11:基于灰色预测和SVR的企业所得税预测分析

【作者主页】Francek Chen 【专栏介绍】 ⌈ ⌈ ⌈机器学习与数据挖掘实战 ⌋ ⌋ ⌋ 机器学习是人工智能的一个分支,专注于让计算机系统通过数据学习和改进。它利用统计和计算方法,使模型能够从数据中自动提取特征并做出预测或决策。数据挖掘则是从大型数据集中发现模式、关联…...

新一代搜索引擎,是 ES 的15倍?

Manticore Search介绍 Manticore Search 是一个使用 C 开发的高性能搜索引擎&#xff0c;创建于 2017 年&#xff0c;其前身是 Sphinx Search 。Manticore Search 充分利用了 Sphinx&#xff0c;显着改进了它的功能&#xff0c;修复了数百个错误&#xff0c;几乎完全重写了代码…...

使用 Context API 管理临时状态,避免 Redux/Zustand 的持久化陷阱

在开发 React Native 应用时&#xff0c;我们经常需要管理全局状态&#xff0c;比如用户信息、主题设置、网络状态等。而对于某些临时状态&#xff0c;例如 数据同步进行中的状态 (isSyncing)&#xff0c;我们应该选择什么方式来管理它&#xff1f; 在项目开发过程中&#xff…...

PyTorch框架——基于深度学习YOLOv8神经网络学生课堂行为检测识别系统

基于YOLOv8深度学习的学生课堂行为检测识别系统&#xff0c;其能识别三种学生课堂行为&#xff1a;names: [举手, 读书, 写字] 具体图片见如下&#xff1a; 第一步&#xff1a;YOLOv8介绍 YOLOv8 是 ultralytics 公司在 2023 年 1月 10 号开源的 YOLOv5 的下一个重大更新版本…...

word2vec 实战应用介绍

Word2Vec 是一种由 Google 在 2013 年推出的重要词嵌入模型,通过将单词映射为低维向量,实现了对自然语言处理任务的高效支持。其核心思想是利用深度学习技术,通过训练大量文本数据,将单词表示为稠密的向量形式,从而捕捉单词之间的语义和语法关系。以下是关于 Word2Vec 实战…...

C# 操作符重载对象详解

.NET学习资料 .NET学习资料 .NET学习资料 一、操作符重载的概念 在 C# 中&#xff0c;操作符重载允许我们为自定义的类或结构体定义操作符的行为。通常&#xff0c;我们熟悉的操作符&#xff0c;如加法&#xff08;&#xff09;、减法&#xff08;-&#xff09;、乘法&#…...

python学opencv|读取图像(五十四)使用cv2.blur()函数实现图像像素均值处理

【1】引言 前序学习进程中&#xff0c;对图像的操作均基于各个像素点上的BGR值不同而展开。 对于彩色图像&#xff0c;每个像素点上的BGR值为三个整数&#xff0c;因为是三通道图像&#xff1b;对于灰度图像&#xff0c;各个像素上的BGR值是一个整数&#xff0c;因为这是单通…...

CNN的各种知识点(四): 非极大值抑制(Non-Maximum Suppression, NMS)

非极大值抑制&#xff08;Non-Maximum Suppression, NMS&#xff09; 1. 非极大值抑制&#xff08;Non-Maximum Suppression, NMS&#xff09;概念&#xff1a;算法步骤&#xff1a;具体例子&#xff1a;PyTorch实现&#xff1a; 总结&#xff1a; 1. 非极大值抑制&#xff08;…...

虚幻基础16:locomotion direction

locomotion locomotion&#xff1a;角色运动系统的总称&#xff1a;包含移动、奔跑、跳跃、转向等。 locomotion direction 玩家输入 玩家输入&#xff1a;通常代表玩家想要的移动方向。 direction 可以计算当前朝向与移动方向的Δ。从而实现朝向与移动(玩家输入)方向的分…...

C++游戏开发实战:从引擎架构到物理碰撞

&#x1f4dd;个人主页&#x1f339;&#xff1a;一ge科研小菜鸡-CSDN博客 &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; 1. 引言 C 是游戏开发中最受欢迎的编程语言之一&#xff0c;因其高性能、低延迟和强大的底层控制能力&#xff0c;被广泛用于游戏…...

代理模式——C++实现

目录 1. 代理模式简介 2. 代码示例 1. 代理模式简介 代理模式是一种行为型模式。 代理模式的定义&#xff1a;由于某些原因需要给某对象提供一个代理以控制该对象的访问。这时&#xff0c;访问对象不适合或者不能直接访问引用目标对象&#xff0c;代理对象作为访问对象和目标…...

什么情况下,C#需要手动进行资源分配和释放?什么又是非托管资源?

扩展&#xff1a;如何使用C#的using语句释放资源&#xff1f;什么是IDisposable接口&#xff1f;与垃圾回收有什么关系&#xff1f;-CSDN博客 托管资源的回收有GC自动触发&#xff0c;而非托管资源需要手动释放。 在 C# 中&#xff0c;非托管资源是指那些不由 CLR&#xff08;…...

LeetCode 2909. 元素和最小的山形三元组 II

**### LeetCode 2909. 元素和最小的山形三元组 II 问题描述 给定一个下标从 0 开始的整数数组 nums&#xff0c;我们需要找到一个“山形三元组”&#xff08;i, j, k&#xff09;满足以下条件&#xff1a; i < j < knums[i] < nums[j] 且 nums[k] < nums[j] 并…...

搬迁至bilibili声明

我将搬迁到bilibili ,用户名&#xff1a;北苏清风 在这个用户名上的文章部分将出自csdn的这个账号&#xff0c;均属于本人原创...

【周易哲学】生辰八字入门讲解(八)

&#x1f60a;你好&#xff0c;我是小航&#xff0c;一个正在变秃、变强的文艺倾年。 &#x1f514;本文讲解【周易哲学】生辰八字入门讲解&#xff0c;期待与你一同探索、学习、进步&#xff0c;一起卷起来叭&#xff01; 目录 一、六亲女命六亲星六亲宫位相互关系 男命六亲星…...

复制粘贴小工具——Ditto

在日常工作中&#xff0c;复制粘贴是常见的操作&#xff0c;但Windows系统自带的剪贴板功能较为有限&#xff0c;只能保存最近一次的复制记录&#xff0c;这对于需要频繁复制粘贴的用户来说不太方便。今天&#xff0c;我们介绍一款开源、免费且功能强大的剪贴板增强工具——Dit…...

3、从langchain到rag

文章目录 本文介绍向量和向量数据库向量向量数据库 索引开始动手实现rag加载文档数据并建立索引将向量存放到向量数据库中检索生成构成一条链 本文介绍 从本节开始&#xff0c;有了上一节的langchain基础学习&#xff0c;接下来使用langchain实现一个rag应用&#xff0c;并稍微…...

稀疏进化训练:机器学习优化算法中的高效解决方案

稀疏进化训练&#xff1a;机器学习优化算法中的高效解决方案 稀疏进化训练&#xff1a;机器学习优化算法中的高效解决方案引言第一部分&#xff1a;背景与动机1.1 传统优化算法的局限性1.2 进化策略的优势1.3 稀疏性的重要性 第二部分&#xff1a;稀疏进化训练的核心思想2.1 稀…...

10 Flink CDC

10 Flink CDC 1. CDC是什么2. CDC 的种类3. 传统CDC与Flink CDC对比4. Flink-CDC 案例5. Flink SQL 方式的案例 1. CDC是什么 CDC 是 Change Data Capture&#xff08;变更数据获取&#xff09;的简称。核心思想是&#xff0c;监测并捕获数据库的变动&#xff08;包括数据或数…...

【LeetCode 刷题】回溯算法-子集问题

此博客为《代码随想录》二叉树章节的学习笔记&#xff0c;主要内容为回溯算法子集问题相关的题目解析。 文章目录 78.子集90.子集II 78.子集 题目链接 class Solution:def subsets(self, nums: List[int]) -> List[List[int]]:res, path [], []def dfs(start: int) ->…...

OpenCV 版本不兼容导致的问题

问题和解决方案 今天运行如下代码&#xff0c;发生了意外的错误&#xff0c;代码如下&#xff0c;其中输入的 frame 来自于 OpenCV 开启数据流的读取 """ cap cv2.VideoCapture(RTSP_URL) print("链接视频流完成") while True:ret, frame cap.rea…...

低成本、高附加值,具有较强的可扩展性和流通便利性的行业

目录 虚拟资源类 1. 网课教程 2. 设计素材 3. 软件工具 服务类 1. 写作服务 2. 咨询顾问 3. 在线教育 4. 社交媒体管理 虚拟资源类 1. 网课教程 特点&#xff1a;高附加值&#xff0c;可复制性强&#xff0c;市场需求大。 执行流程&#xff1a; 选择领域&#xff1a…...

DirectShow过滤器开发-读视频文件过滤器(再写)

下载本过滤器DLL 本过滤器读取视频文件输出视频流和音频流。流类型由文件决定。已知可读取的文件格式有&#xff1a;AVI&#xff0c;ASF&#xff0c;MOV&#xff0c;MP4&#xff0c;MPG&#xff0c;WMV。 过滤器信息 过滤器名称&#xff1a;读视频文件 过滤器GUID&#xff1a…...

代码练习2.3

终端输入10个学生成绩&#xff0c;使用冒泡排序对学生成绩从低到高排序 #include <stdio.h>void bubbleSort(int arr[], int n) {for (int i 0; i < n-1; i) {for (int j 0; j < n-i-1; j) {if (arr[j] > arr[j1]) {// 交换 arr[j] 和 arr[j1]int temp arr[…...

基于 Redis GEO 实现条件分页查询用户附近的场馆列表

&#x1f3af; 本文档详细介绍了如何使用Redis GEO模块实现场馆位置的存储与查询&#xff0c;以支持“附近场馆”搜索功能。首先&#xff0c;通过微信小程序获取用户当前位置&#xff0c;并将该位置信息与场馆的经纬度数据一同存储至Redis中。利用Redis GEO高效的地理空间索引能…...

【大数据技术】案例01:词频统计样例(hadoop+mapreduce+yarn)

词频统计(hadoop+mapreduce+yarn) 搭建完全分布式高可用大数据集群(VMware+CentOS+FinalShell) 搭建完全分布式高可用大数据集群(Hadoop+MapReduce+Yarn) 在阅读本文前,请确保已经阅读过以上两篇文章,成功搭建了Hadoop+MapReduce+Yarn的大数据集群环境。 写在前面 Wo…...

Selenium 使用指南:从入门到精通

Selenium 使用指南&#xff1a;从入门到精通 Selenium 是一个用于自动化 Web 浏览器操作的强大工具&#xff0c;广泛应用于自动化测试和 Web 数据爬取中。本文将带你从入门到精通地掌握 Selenium&#xff0c;涵盖其基本操作、常用用法以及一个完整的图片爬取示例。 1. 环境配…...

笔试-排列组合

应用 一个长度为[1, 50]、元素都是字符串的非空数组&#xff0c;每个字符串的长度为[1, 30]&#xff0c;代表非负整数&#xff0c;元素可以以“0”开头。例如&#xff1a;[“13”, “045”&#xff0c;“09”&#xff0c;“56”]。 将所有字符串排列组合&#xff0c;拼起来组成…...