leetcode 3.11

leetcode hot 100

    • 二分查找
      • 1.寻找旋转排序数组中的最小值
    • 矩阵
      • 1.搜索二维矩阵 II
        • 知识点:upper_bound, lower_bound
        • 知识点:二分查找
      • 2.搜索二维矩阵
    • 链表
      • 1.合并两个有序链表
      • 2.两数相加
      • 3. 删除链表的倒数第 N 个结点

二分查找

1.寻找旋转排序数组中的最小值

寻找旋转排序数组中的最小值
根据题意可知,一定存在一个点,让整个数组断崖式下跌,
[7, 6, 5, 4, 3, 2, 0, 1] 比如在这个数组中的0
我们需要找到这个断崖式下跌的点,就是这个数组的最小值
在这里插入图片描述
我们考虑数组中的最后一个元素 x:在最小值右侧的元素(不包括最后一个元素本身),它们的值一定都严格小于 x;而在最小值左侧的元素,它们的值一定都严格大于 x。因此,我们可以根据这一条性质,通过二分查找的方法找出最小值。
查找第一个大于等于目标值的元素(加了其它代码的解释,原来的题解放在链接里了)

class Solution {
public:int findMin(vector<int>& nums) {int low  = 0; int high = nums.size() - 1;while (low  < high) {int pivot = low + (high - low) / 2;if (nums[pivot] < nums[high]) {high = pivot;} else {low  = pivot + 1;}}return nums[low];}
};

矩阵

1.搜索二维矩阵 II

240. 搜索二维矩阵 II

第一种:最容易想到的暴力解法
时间复杂度:o(mn)
空间复杂度:o(1)

第二种:暴力解法的进阶版,用二分查找每一行,这样可以减少时间复杂度
时间复杂度:o(nlogn)
空间复杂度:o(1)

第三种:比较巧妙的方法,从左上或者右下角开始查找,以右下角matrix[n - 1][0] 为例,如果当前matrix[i][j] 值为 a

  • 如果我们找的元素target大于a,那么 j++ 寻找
  • 如果我们找的元素target小于a,那么 i-- 寻找
  • 如果等于,则直接返回

第二种: 二分优化暴力查找

class Solution {
public:bool searchMatrix(vector<vector<int>>& matrix, int target) {int n = matrix.size(), m = matrix[0].size();for (int i = 0; i < n; i++) {auto ans = lower_bound(matrix[i].begin(), matrix[i].end(), target);//auto tmp = ans - matrix[i].begin();//if (ans != matrix[i].end() &&  matrix[i][tmp] == target) {if (ans != matrix[i].end() && *ans == target) {return true;}}return false;}
};

或者不用库函数,手写二分:

class Solution {
public:bool searchMatrix(vector<vector<int>>& matrix, int target) {int n = matrix.size(), m = matrix[0].size();for (int i = 0; i < n; i++) {int l = 0, r = m;while (l < r) {int mid = (r - l) / 2 + l;if (matrix[i][mid] < target) {l = mid + 1;} else {r = mid;}}if (l < m && matrix[i][l] == target) return true;}return false;}
};
class Solution {
public:bool searchMatrix(vector<vector<int>>& matrix, int target) {int n = matrix.size(), m = matrix[0].size();for (int i = 0; i < n; i++) {int l = 0, r = m - 1;while (l <= r) {int mid = (r - l) / 2 + l;if (matrix[i][mid] < target) {l = mid + 1;} else  if (matrix[i][mid] > target) {r = mid - 1;} else {return true;}}}return false;}
};
知识点:upper_bound, lower_bound

upper_bound, lower_bound两者都是定义在头文件里。用 二分查找的方法在一个排好序的数组中进行查找。既然是二分,时间复杂度就是O(logN)。

基础用法

upper_bound(begin, end, value)

从小到大的排好序的数组中,在数组的 [begin, end) 区间中二分查找第一个大于value的数,找到返回该数字的地址,没找到则返回end。

lower_bound(begin, end, value)

在从小到大的排好序的数组中,在数组的 [begin, end) 区间中二分查找第一个大于等于value的数,找到返回该数字的地址,没找到则返回end。

用greater()重载

upper_bound(begin, end, value, greater<int>())

在从大到小的排好序的数组中,在数组的 [begin, end) 区间中二分查找第一个小于value的数,找到返回该数字的地址,没找到则返回end。

lower_bound(begin, end, value, greater<int>())

在从大到小的排好序的数组中,在数组的 [begin, end) 区间中二分查找第一个小于等于value的数,找到返回该数字的地址,没找到则返回end。

第三种:将二维矩阵抽象成「以右上角为根的 BST」

以右上为根

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

以左下为根……

class Solution {
public:bool searchMatrix(vector<vector<int>>& matrix, int target) {int n = matrix.size(), m = matrix[0].size();int i = n - 1, j = 0;while (i >= 0 && j < m) {if (matrix[i][j] > target) i--;else if (matrix[i][j] < target) j++;else return true;}return false;}
};
知识点:二分查找

二分查找的难点在于边界判断,如果实在没法判断可以写几个数字自己模拟二分过程推导一次就能得出结论。以下为个人总结,仅供参考

记住两个模板,在这两个模板上修改:
当我们需要查找第一个大于等于target的数时:

  • 第一种方法:
    • r = n
    • l < r不加等号,这样l == r 时会返回
    • 需要判断 >= target 的情况,因为如果用<=会导致死循环
    • return l/ r
int l = 0, r = n;
while (l < r) {......if (nums[mid] >= targer) {r = mid;} else {l = mid + 1;}
}
  • 第二种方法:
    • r = n - 1
    • l <= r 加等号,这样l > r (l > r && r - l = 1) 时会返回
    • 加上 == target 的情况判断会比较清晰(个人习惯)
    • return l (也就是r + 1)
int l = 0, r = n - 1;
while (l <= r) {......if (nums[mid] == target) {return mid + 1;} else if (nums[mid] < target) {l = mid + 1;} else {r = mid - 1;}
}
return l;

当我们需要查找第一个大于target的数时:

  • 第一种方法:
    • r = n
    • l < r不加等号,这样l == r 时会返回
    • 需要判断 >= target 的情况,因为如果用<=会导致死循环
    • 判断结果,如果等于则return l + 1, 否则return l (也就是r + 1)
int l = 0, r = n;
while (l < r) {......if (nums[mid] >= targer) {r = mid;} else {l = mid + 1;}
}
  • 第二种方法:
    • r = n - 1
    • l <= r 加等号,这样l > r (l > r && r - l = 1) 时会返回
    • 加上 == target 的情况判断会比较清晰(个人习惯)
    • 判断结果,如果等于则return mid + 1, 否则return l (也就是r + 1)
int l = 0, r = n - 1;
while (l <= r) {......if (nums[mid] == target) {return mid + 1;} else if (nums[mid] < target) {l = mid + 1;} else {r = mid - 1;}
}
return l;

同理可以推出其他情况。

现在让我们用抽象成BST的方法来重新做以下这道题

2.搜索二维矩阵

搜索二维矩阵
我们从以右上为根节点

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

链表

1.合并两个有序链表

合并两个有序链表
方法一:迭代
当 list1 和 list2都不为空时,依次连接,之后判断哪个链表不为空,把剩余链表合并。
时间复杂度:O(n+m)
空间复杂度:O(1)

/*** Definition for singly-linked list.* 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* mergeTwoLists(ListNode* list1, ListNode* list2) {ListNode* dummy = new ListNode(-1);ListNode* ans = dummy;while (list1 != nullptr && list2 != nullptr) {if (list1->val < list2->val) {ans->next = list1;list1 = list1->next;} else {ans->next = list2;list2 = list2->next;}ans = ans->next;}ans->next = list1 == nullptr ? list2 : list1;return dummy->next;}
};

方法二:递归

一开始并没有想到这个递归方法,所以需要再次复习递归的知识点:

  • 递归函数必须要有终止条件,否则会出错;
  • 递归函数先不断调用自身,直到遇到终止条件后进行回溯,最终返回答案。

在此题中,终止条件就是list1 == nullptr || list2 == nullptr
我们可以如下递归地定义两个链表里的 merge 操作(忽略边界情况,比如空链表等):

  • list1[0] + merge(list1[1:], list2) list1[0] < list2[0]
  • list2[0] + merge(list1, list2[1:]) otherwise

也就是说,两个链表头部值较小的一个节点与剩下元素的 merge 操作结果合并。

/*** Definition for singly-linked list.* 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* mergeTwoLists(ListNode* list1, ListNode* list2) {if (list1 == nullptr) return list2;else if (list2 == nullptr) return list1;else if (list1->val < list2->val) {list1->next = mergeTwoLists(list1->next, list2);return list1;} else {list2->next = mergeTwoLists(list1, list2->next);return list2;}}
};

2.两数相加

两数相加
暴力思路:先把链表转为int, 加起来之后再放到int里,那肯定是会超时/超空间的
看了题解可以发现:
1.如果遍历到某个链表之后为空,值为0
2.链表每一位上的和为 (list1->val + list2->val + carry)% 10,carry为上一位的进位,初始值为0
3.链表每一位上的进位为 carry = (list1->val + list2->val + carry) / 10
4.因为是逆序存储,那么直接计算,如果最后一位有进位,那么end->next后再new 一个 node(1)

/*** Definition for singly-linked list.* 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* addTwoNumbers(ListNode* l1, ListNode* l2) {ListNode* dummy = new ListNode(-1);ListNode* result = dummy;int carry = 0;while (l1 != nullptr || l2 != nullptr) {int x = l1 == nullptr ? 0 : l1->val;int y = l2 == nullptr ? 0 : l2->val;int tmp = (x + y + carry) % 10;result->next = new ListNode(tmp);result = result->next;carry = (x + y + carry) / 10;if (l1 != nullptr) l1 = l1->next;if (l2 != nullptr) l2 = l2->next;}if (carry) result->next = new ListNode(1);return dummy->next;}
};

3. 删除链表的倒数第 N 个结点

删除链表的倒数第 N 个结点
第一次遍历得出链表个数,第二次遍历删除节点

/*** Definition for singly-linked list.* 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* removeNthFromEnd(ListNode* head, int n) {ListNode* p = head, *q = head;int num = 0;while(p != nullptr) {p = p->next;num++;}// 如果要删除的节点是第一个节点,直接返回第二个节点即可if (num == n) return head->next;num = num - n - 1;while (num--) {q = q->next;}//如果要删除的是最后一个节点之后的节点,空节点,直接return headif (q->next != nullptr)q->next = q->next->next;return head;}
};

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

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

相关文章

【C#】.net core 6.0 使用第三方日志插件Log4net,日志输出到控制台或者文本文档

欢迎来到《小5讲堂》 大家好&#xff0c;我是全栈小5。 这是《C#》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解&#xff0c; 特别是针对知识点的概念进行叙说&#xff0c;大部分文章将会对这些概念进行实际例子验证&#xff0c;以此达到加深对知识点的理解和掌握。…

鸿蒙Next学习-Flex布局

Entry Component struct FlexCase {build() {//需要在构造参数上传Flex({ direction: FlexDirection.Row,justifyContent:FlexAlign.Center }) {//flex布局Row().width(100).height(100).backgroundColor(Color.Red)Row().width(100).height(100).backgroundColor(Color.Yellow…

c++11语法特性

c11 1.c11发展简介 ​ 第一个比较正式的c标准是1998提出的c98标准。之后定了5年计划&#xff0c;每5年来一次大更新。在2003年C标准委员会曾经提交了一份技术勘误表(简称TC1)&#xff0c;使得C03这个名字已经取代了C98称为C11之前的最新C标准名称。不过由于C03(TC1)主要是对C…

工作中Git如何切换远程仓库地址

工作中Git如何切换远程仓库地址 部门之前的仓库不用了&#xff0c;重新建了一个仓库&#xff0c;但是上传代码还是上传到了之前的仓库里面了&#xff0c;所以得进行修改&#xff0c;下面将修改地址的方法进行操作。 方法一、直接修改远程仓库地址 查看当前远程仓库地址 git …

使用 ChatGPT 写高考作文

写作文&#xff0c;很简单&#xff0c;但写一篇好的作文&#xff0c;是非常有难度的。 想要写一篇高分作文&#xff0c;需要对作文题目有正确的理解&#xff0c;需要展现独到的观点和深入的思考&#xff0c;需要具备清晰的逻辑结构&#xff0c;需要准确而得体的语言表达。 正…

【Linux进阶之路】HTTPS = HTTP + S

文章目录 一、概念铺垫1.Session ID2.明文与密文3.公钥与私钥4.HTTPS结构 二、加密方式1. 对称加密2.非对称加密3.CA证书 总结尾序 一、概念铺垫 1.Session ID Session ID&#xff0c;即会话ID&#xff0c;用于标识客户端与服务端的唯一特定会话的标识符。会话&#xff0c;即客…

LeetCode 热题 100 | 回溯(二)

目录 1 39. 组合总和 2 22. 括号生成 3 79. 单词搜索 菜鸟做题&#xff0c;语言是 C&#xff0c;感冒快好版 关于对回溯算法的理解请参照我的上一篇博客&#xff1b; 在之后的博客中&#xff0c;我将只分析回溯算法中的 for 循环。 1 39. 组合总和 题眼&#xff1a;c…

15届蓝桥杯第二期模拟赛题单详细解析

文章目录 &#x1f9e1;&#x1f9e1;t1_求余&#x1f9e1;&#x1f9e1;思路代码 &#x1f9e1;&#x1f9e1;t2_灌水&#x1f9e1;&#x1f9e1;思路代码 &#x1f9e1;&#x1f9e1;t3_字符显示&#x1f9e1;&#x1f9e1;思路代码 &#x1f9e1;&#x1f9e1;t4_区间最大和…

网络计算机

TCP/IP四层模型 应用层&#xff1a;位于传输层之上&#xff0c;主要提供两个设备上的应用程序之间信息交换的服务&#xff0c;它定义了信息交换的格式&#xff0c;消息会交给下一层传输层来传递。我们把应用层交互的数据单元称为报文。应用层工作在操作系统的用户态&#xff0…

YOLOv8_pose-Openvino和ONNXRuntime推理【CPU】

纯检测系列&#xff1a; YOLOv5-Openvino和ONNXRuntime推理【CPU】 YOLOv6-Openvino和ONNXRuntime推理【CPU】 YOLOv8-Openvino和ONNXRuntime推理【CPU】 YOLOv7-Openvino和ONNXRuntime推理【CPU】 YOLOv9-Openvino和ONNXRuntime推理【CPU】 跟踪系列&#xff1a; YOLOv5/6/7-O…

Android 音频系统

导入 早期Linux版本采用的是OSS框架&#xff0c;它也是Unix及类Unix系统中广泛使用的一种音频体系。 ALSA是Linux社区为了取代OSS而提出的一种框架&#xff0c;是一个源代码完全开放的系统(遵循GNU GPL和GNU LGPL)。ALSA在Kernel 2.5版本中被正式引入后&#xff0c;OSS就逐步…

C语言:操作符详解(下)

目录 一、逗号表达式二、下标访问[ ]、函数调用()1. [ ]下标引用操作符2.函数调用操作符 三、结构成员访问操作符1.结构体(1) 结构的声明(2) 结构体变量的定义和初始化 2.结构成员访问操作符(1)结构体成员的直接访问(2)结构体成员的间接访问 四、操作符的属性&#xff1a;优先级…

Rudolf and the Ball Game

传送门 题意 思路 暴力枚举每一个妆台的转换条件 code #include<iostream> #include<cstdio> #include<stack> #include<vector> #include<algorithm> #include<cmath> #include<queue> #include<cstring> #include<ma…

【Docker】容器的生态系统

Docker提供了一整套技术支持&#xff0c;包括核心技术、平台技术、支持技术。 核心技术 容器核心技术是指能让Container&#xff08;容器&#xff09;在host&#xff08;集群、主机&#xff09;上运行起来的那些技术。 1&#xff09;容器规范&#xff1a;OCI&#xff08;runt…

搭建mysql主从复制(主主复制)

1&#xff1a;设主库允许远程连接(注意&#xff1a;设置账号密码必须使用的插件是mysql_native_password&#xff0c;其他的会连接失败) #切换到mysql这个数据库&#xff0c;修改user表中的host&#xff0c;使其可以实现远程连接 mysql>use mysql; mysql>update user se…

基于YOLOv8/YOLOv7/YOLOv6/YOLOv5的零售柜商品检测软件(Python+PySide6界面+训练代码)

摘要&#xff1a;开发高效的零售柜商品识别系统对于智能零售领域的进步至关重要。本文深入介绍了如何运用深度学习技术开发此类系统&#xff0c;并分享了全套实现代码。系统采用了领先的YOLOv8算法&#xff0c;并与YOLOv7、YOLOv6、YOLOv5进行了性能比较&#xff0c;呈现了诸如…

蓝桥杯每日一题:血色先锋队

今天浅浅复习巩固一下bfs 答案&#xff1a; #include<iostream> #include<algorithm> #include<cstring>using namespace std; typedef pair<int,int> PII;const int N510; int n,m,a,b; int dist[N][N]; PII q[N*N]; int hh0,tt-1;int dx[]{1,0,-1,…

网络层:地址解析协议ARP、网际控制报文协议ICMP、虚拟专用网络VPN、网络地址转换NAT

文章目录 地址解析协议ARP解决的问题ARP解析流程ARP高速缓存 网际控制报文协议ICMPICMP报文的种类ICMP差错报告报文ICMP询问报文 ICMP应用举例分组网间探测PING(Packet InterNet Groper)traceroute(tracert)确定路径的MTU 虚拟专用网络专用地址虚拟专用网络远程接入VPN(remote …

某鱼弹幕逆向

声明: 本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;不提供完整代码&#xff0c;抓包内容、敏感网址、数据接口等均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff01;wx a15018…

mysql题库详解

1、如何创建和删除数据库&#xff1f; 创建数据库 CREATE DATABASE 数据库名; 删除数据库 drop database 数据库名; 2、MyISAM与InnoDB的区别&#xff1f; 1&#xff09;事务&#xff1a;MyISAM 不支持事务 InnoDB 支持 2&#xff09;行锁/表锁&#xff1a;MyISAM 支持表级锁…