hot100 -- 二分查找

2024-06-09 08:44
文章标签 二分 查找 hot100

本文主要是介绍hot100 -- 二分查找,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

前言

🎂搜索插入位置

🌼搜索二维矩阵

🌼排序数组元素第一和最后一个位置

🌼旋转排序数组

💪旋转排序数组中的最小值

💪两个正序数组的中位数


前言

二分算法学习_时间超限ac:0%-CSDN博客

🎂搜索插入位置

35. 搜索插入位置 - 力扣(LeetCode)

直接套博客里的万能模板不太行,万能模板只能处理下取整死循环的问题,但是本题:

目标值 target 不一定在数组里

class Solution {
public:int searchInsert(vector<int>& nums, int target) {int l = 0, r = nums.size() - 1;while (l <= r) {int m = (l + r) >> 1;if (target > nums[m])l = m + 1;else if (target < nums[m])r = m - 1;else {l = m;break;}}// 因为 l<=r 退出循环后, r 必然位于插入位置return l;}
};

🌼搜索二维矩阵

74. 搜索二维矩阵 - 力扣(LeetCode)

1)别混淆 mid 和 m,此处 m 是 m 行,mid 才是中间值

2)对第 3 种情况,target == matrix[][],进行处理

class Solution {
public:bool searchMatrix(vector<vector<int>>& matrix, int target) {int m = matrix.size(), n = matrix[0].size();int l = 0, r = m*n - 1; // 二维转一维while (l < r) {int mid = (l + r + 1) >> 1;if (target > matrix[mid/n][mid%n]) // 一维转二维l = mid;else if (target < matrix[mid/n][mid%n])r = mid - 1;else {l = mid;break;}}return matrix[l/n][l%n] == target;}
};

🌼排序数组元素第一和最后一个位置

34. 在排序数组中查找元素的第一个和最后一个位置 - 力扣(LeetCode)

1)利用 while (l <= r) { ... l = m + 1 ... r = m - 1 };  左闭右闭区间

退出循环时,l 的位置就是 >= target 的最小的数

r == l - 1

2)只需求出第一个位置,即可取巧得到最后一个位置,现在有二分函数 lowerbound(nums, target) 得到第一个位置,最后一个位置即 lowerbound(nums, target + 1) - 1

3)奇数个元素,m = (l + r) / 2,取到中间的元素;偶数个元素,因为整数默认下取整,会取中间两个元素左边那个

坑:

1)不要用 >> 1,要用 / 2,不知道力扣是不是不支持位移运算符(>> 1 会超出时间限制) 

2)如果想要从 r = m - 1 开始,那么最后应该 return r;   r 此时位于最后一个位置(详情看代码 2)(用例1模拟一下)

代码 1

class Solution {
public:// >= target 的最小的数的位置int lowerbound(vector<int>& nums, int target) {int l = 0, r = nums.size() - 1;while (l <= r) {int m = l + (r - l) / 2;if (target > nums[m])l = m + 1;elser = m - 1;}return l; // 第一个位置}vector<int> searchRange(vector<int>& nums, int target) {int start = lowerbound(nums, target);if (start >= nums.size() || nums[start] != target)return {-1, -1};int end = lowerbound(nums, target + 1) - 1;return {start, end};}
};

代码 2

class Solution {
public:// >= target 的最小的数的位置int lowerbound(vector<int>& nums, int target) {int l = 0, r = nums.size() - 1;while (l <= r) {int m = l + (r - l) / 2;if (target < nums[m])r = m - 1;elsel = m + 1;}return r; // 最后一个位置}vector<int> searchRange(vector<int>& nums, int target) {int end = lowerbound(nums, target);if (end < 0 || nums[end] != target)return {-1, -1};int start = lowerbound(nums, target - 1) + 1;return {start, end};}
};

🌼旋转排序数组

33. 搜索旋转排序数组 - 力扣(LeetCode)

1)二分时,套 while (l <= r) 的模板,mid 位于中间 OR 中间偏左位置

此时,[l, mid] OR [mid + 1, r],至少一个区间是有序的,所以对左右区间的有序分类讨论

class Solution {
public:int search(vector<int>& nums, int target) {int n = nums.size();int l = 0, r = n - 1;// 二分找到 k 的位置while (l <= r) {int mid = (l + r) / 2;// target 位于 midif (nums[mid] == target)return mid;// 左边有序else if (nums[l] <= nums[mid]) {// target 位于左边(不包括 mid)if (nums[l] <= target && target < nums[mid]) r = mid - 1;else l = mid + 1;}// 右边有序else {// target 位于右边(不包括 mid)if (nums[mid] < target && target <= nums[r])l = mid + 1;elser = mid - 1;}}return -1; // 未找到}
};

💪旋转排序数组中的最小值

153. 寻找旋转排序数组中的最小值 - 力扣(LeetCode)

上一题是找目标值,本题是找最小值(都满足部分有序)

本题每次旋转,将最后一个值提取到最前面

可以画几个例子多验证一下:2 0 1,1 2 0,3 4 5 2,5 2 3 4

最小值处于断崖的第一个位置,显而易见,肯定位于无序一边

所以每次压缩有序部分,到无序部分找,注意结合例子处理边界

class Solution {
public:int findMin(vector<int>& nums) {int n = nums.size();int l = 0, r = n - 1;while (l <= r) { // l < r 也行// 单调升序if (nums[l] <= nums[r]) // 用 = 防止单个元素时死循环return nums[l];int m = (l + r) / 2;// 左边有序if (nums[m] >= nums[l]) // 用 = 防止 r 跳过最小值l = m + 1; // 去右边找elser = m; // 不用 m-1 防止跳过最小值}return nums[l];}
};

💪两个正序数组的中位数

4. 寻找两个正序数组的中位数 - 力扣(LeetCode)

结合这篇博客理解一下,用删除(淘汰)的思路
寻找两个正序数组的中位数(292) | 小浩算法 (geekxh.com)

辅助数组 findKth(nums1, i, nums2, j, k),i, j 是两个数组起始索引,第 k 大元素

如果第一个数组起始位置 i + 2/k - 1 的值 < 第二个数组起始位置 j + 2/k - 1 的值

那么就淘汰掉第一个数组前 2/k 个元素,反之淘汰另一个数组前 2/k 个元素

直到 k == 1,此时比较两个数组起始第 1 个元素大小即可

或者一个数组为空(即 i >= nums1.size() 或 j >= nums2.size())

时间 O(log( max(m, n) ))

class Solution {
public:double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {int n = nums1.size(), m = nums2.size();int left = (n + m + 1) / 2, right = (n + m + 2) / 2; // 中间值索引 left 和 rightreturn (findKth(nums1, 0, nums2, 0, left) + findKth(nums1, 0, nums2, 0, right)) / 2.0;}// nums1 起始索引 i, nums2 起始索引 j, 返回合并数组 第 k 个元素(1开始算)int findKth(vector<int>& nums1, int i, vector<int>& nums2, int j, int k) {if (i >= nums1.size()) // nums1 空数组return nums2[j + k - 1];if (j >= nums2.size()) // nums2 空数组return nums1[i + k - 1];if (k == 1)return min(nums1[i], nums2[j]); // 返回较小值// 2/k 位置的值// 如果一个数组 k/2 处超出范围, 无法判断中位数是否位于这个数组// 但是另一个数组前 k/2 个肯定没有中位数// 取 MAX, 淘汰另一个数组前 k/2 个元素int mid1 = (i + k/2 - 1 < nums1.size()) ? nums1[i + k/2 - 1] : INT_MAX;int mid2 = (j + k/2 - 1 < nums2.size()) ? nums2[j + k/2 - 1] : INT_MAX;// 递归二分if (mid1 < mid2) // mid1 淘汰 k/2return findKth(nums1, i + k/2, nums2, j, k - k/2);else // mid2 淘汰 k/2return findKth(nums1, i, nums2, j + k/2, k - k/2);}
};

这篇关于hot100 -- 二分查找的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1044705

相关文章

MySQL中查找重复值的实现

《MySQL中查找重复值的实现》查找重复值是一项常见需求,比如在数据清理、数据分析、数据质量检查等场景下,我们常常需要找出表中某列或多列的重复值,具有一定的参考价值,感兴趣的可以了解一下... 目录技术背景实现步骤方法一:使用GROUP BY和HAVING子句方法二:仅返回重复值方法三:返回完整记录方法四:

C++作用域和标识符查找规则详解

《C++作用域和标识符查找规则详解》在C++中,作用域(Scope)和标识符查找(IdentifierLookup)是理解代码行为的重要概念,本文将详细介绍这些规则,并通过实例来说明它们的工作原理,需... 目录作用域标识符查找规则1. 普通查找(Ordinary Lookup)2. 限定查找(Qualif

C#实现查找并删除PDF中的空白页面

《C#实现查找并删除PDF中的空白页面》PDF文件中的空白页并不少见,因为它们有可能是作者有意留下的,也有可能是在处理文档时不小心添加的,下面我们来看看如何使用Spire.PDFfor.NET通过C#... 目录安装 Spire.PDF for .NETC# 查找并删除 PDF 文档中的空白页C# 添加与删

Windows系统下如何查找JDK的安装路径

《Windows系统下如何查找JDK的安装路径》:本文主要介绍Windows系统下如何查找JDK的安装路径,文中介绍了三种方法,分别是通过命令行检查、使用verbose选项查找jre目录、以及查看... 目录一、确认是否安装了JDK二、查找路径三、另外一种方式如果很久之前安装了JDK,或者在别人的电脑上,想

hdu2241(二分+合并数组)

题意:判断是否存在a+b+c = x,a,b,c分别属于集合A,B,C 如果用暴力会超时,所以这里用到了数组合并,将b,c数组合并成d,d数组存的是b,c数组元素的和,然后对d数组进行二分就可以了 代码如下(附注释): #include<iostream>#include<algorithm>#include<cstring>#include<stack>#include<que

hdu2289(简单二分)

虽说是简单二分,但是我还是wa死了  题意:已知圆台的体积,求高度 首先要知道圆台体积怎么求:设上下底的半径分别为r1,r2,高为h,V = PI*(r1*r1+r1*r2+r2*r2)*h/3 然后以h进行二分 代码如下: #include<iostream>#include<algorithm>#include<cstring>#include<stack>#includ

poj 2976 分数规划二分贪心(部分对总体的贡献度) poj 3111

poj 2976: 题意: 在n场考试中,每场考试共有b题,答对的题目有a题。 允许去掉k场考试,求能达到的最高正确率是多少。 解析: 假设已知准确率为x,则每场考试对于准确率的贡献值为: a - b * x,将贡献值大的排序排在前面舍弃掉后k个。 然后二分x就行了。 代码: #include <iostream>#include <cstdio>#incl

poj 3104 二分答案

题意: n件湿度为num的衣服,每秒钟自己可以蒸发掉1个湿度。 然而如果使用了暖炉,每秒可以烧掉k个湿度,但不计算蒸发了。 现在问这么多的衣服,怎么烧事件最短。 解析: 二分答案咯。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <c

poj 3258 二分最小值最大

题意: 有一些石头排成一条线,第一个和最后一个不能去掉。 其余的共可以去掉m块,要使去掉后石头间距的最小值最大。 解析: 二分石头,最小值最大。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <c

poj 2594 二分图最大独立集

题意: 求一张图的最大独立集,这题不同的地方在于,间接相邻的点也可以有一条边,所以用floyd来把间接相邻的边也连起来。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#include <sta