二分搜索也是一个很有趣的专题,被做过的题中,刚好一个Easy,一个Medium和一个Hard,刚好可以看看,二分搜索的三个难度等级都是啥样的。

124. Binary Tree Maximum Path Sum[Hard](详见二叉树专题)

先来看Hard,一看不对劲,这一题和二分搜索不能说是毫无关系,只能说毫不相关,这就是个纯纯的二叉树的题,赶紧从这个专题剔除,写到二叉树专题里了

Leetcode百题斩-二叉树-最大路径和-CSDN博客

35. Search Insert Position[Easy]

思路:经典二分,求大于等于当前数的第一个位置,果然easy题,那么直接来

/*
Author Owen_Q
*/
public class InsertSearcher {public static int searchInsert(int[] nums, int target) {int en = nums.length - 1;int st = 0;int mid = (st + en) / 2;while (st <= en) {if (nums[mid] == target) {return mid;} else if (nums[mid] > target) {en = mid - 1;} else {st = mid + 1;}mid = (st + en) / 2;}return st;}
}

多想一步:考虑元素可重通用写法

 既然是easy题,这一题其实也很有代表性了,那么我们就多想一步,考虑一下当元素可重时的通用写法,就是将等于mid的场景直接去掉。这样就可以形成通用模板了,说不定后面还能用到

/*
Author Owen_Q
*/
public class InsertSearcher {public static int accurateSearchInsert(int[] nums, int target) {int en = nums.length - 1;int st = 0;while (st <= en) {int mid = (st + en) / 2;if (nums[mid] >= target) {en = mid - 1;} else {st = mid + 1;}}return st;}
}

33. Search in Rotated Sorted Array[Medium]

思路:将数组旋转,然后求当前元素是否在数组中。经典二分的变种题,分情况讨论一下即可

首先特判mid,st和en三个点,如果找到直接返回。

我们的目标就是为了找到target个mid的关系,从而缩小二分的区间

下面,我们主要讨论值在左边的场景,因为值在右边的场景把值在左边的场景排除掉即可获得

首先,我们可以根据target和num[mid]的大小关系来进行分类,然后再根据mid在大小分界的左边还是右边进行分类

  • 当target<num[mid]时,
    • 我们先假设mid在分界的左侧(num[en] < num[st] < num[mid]),那么此时mid的左侧有序,此时如果希望target在mid左侧,那么target一定得大于num[st],否则,若target再小一点就会转到右边去了,即target > num[st] 
    • 我们再假设num[mid]在分界的右侧(num[mid] < num[en] < num[st] ),此时左侧无序了,右侧有序了,那么此时我们不难发现,这种情况肯定没法在右侧。于是只需要找到这种情况即可。即num[st] > num[mid] 
  • 当target>num[mid]时
    • 还是一样,我们先假设mid在分界的左侧(num[en] < num[st] < num[mid]),此时mid的左侧有序,那么num[mid]就是最大值,而target比最大值还大,显然不成立
    • 由此可知,此时mid一定在分界的右侧(num[mid] < num[en] < num[st]),那么mid右侧有序,此时,target值一定要大于num[st],确保其转到左边去
/*
Author Owen_Q
*/
public class RotatedSearcher {public static int search(int[] nums, int target) {int en = nums.length - 1;int st = 0;int mid = (st + en) / 2;while (st <= en) {if (nums[mid] == target) {return mid;} else if (nums[st] == target) {return st;} else if (nums[en] == target) {return en;} else if ((nums[mid] > target && ((nums[st] < target) || nums[st] > nums[mid])) || (nums[mid] < target && nums[mid] < nums[st] && nums[st] < target)) {en = mid - 1;} else {st = mid + 1;}mid = (st + en) / 2;}return -1;}
}

153. Find Minimum in Rotated Sorted Array[Medium]

思路:寻找旋转数组中的最小值

依旧是分情况讨论。

首先我们先找一种最简单的情况,就是数组内部有序,即nums[st] \leqslant nums[mid] \leq nums[en],那么此时可以直接退出二分,因为st就是最小值所在点

接下来,我们看一下两种常规情况 

第一种就是当前搜索到的值比两侧都大,即nums[mid] \geq nums[st] \wedge nums[mid] \geq nums[en],那么此时最小值一定在右侧

第二种则是当搜索到的值比两侧都小,即nums[mid] \leq nums[st] \wedge nums[mid] \leq nums[en],那么此时最小值要么在左侧,要么自身就是最小值

/*
Author Owen_Q
*/
public class RotatedMinimum {public static int findMin(int[] nums) {int st = 0;int en = nums.length - 1;int mid = (st + en) / 2;while (st <= en) {if (nums[st] <= nums[mid] && nums[mid] <= nums[en]) {return nums[st];} else if (nums[mid] >= nums[st] && nums[mid] >= nums[en]) {st = mid + 1;} else {en = mid;}mid = (st + en) / 2;}return nums[st];}
}

74. Search a 2D Matrix[Medium](详见矩阵专题)

思路:这一题极其熟悉,是不是之前做过,果然,在矩阵专题里有原题,还是线性复杂度的,那既然有更好的做法,就不看这里log复杂度的二分方案了

Leetcode百题斩-矩阵-矩阵搜索-CSDN博客

34. Find First and Last Position of Element in Sorted Array[Medium]

思路:寻找元素在数组中的区间。这刚好上面多想一步的模版就可以用上了。模版的内容是找到大于等于当前数的第一个值,刚好可以作为区间起点,区间终点就是大于等于下一个数的前一个位置。若当前数不在区间中,那么大于等于当前数和大于等于下一个数一定是同一个位置,区间终点建议后会导致右区间大于左区间,直接特判找不到即可

/*
Author Owen_Q
*/
public class RangeSearcher {public static int[] searchRange(int[] nums, int target) {int[] result = new int[2];result[0] = InsertSearcher.accurateSearchInsert(nums, target);result[1] = InsertSearcher.accurateSearchInsert(nums, target + 1) - 1;if (result[0] > result[1]) {result[0] = -1;result[1] = -1;}return result;}
}

4. Median of Two Sorted Arrays[Hard]

思路:给定两个有序数组,要求在log时间复杂度内寻找中位数。换个思路,寻找中位数,思路上来说就是寻找两数组合并后的中间两个数求个平均值。针对长度为 nums1Len 和 nums2Len 的数组,中间的位置就在 \frac{nums1Len + nums2Len}{2} 和 \frac{nums1Len + nums2Len - 1}{2}。于是,问题转化为,如何求两个有序数组的第 k 个位置的值。如果直接将俩数组合并,那妥妥线性复杂度,如何利用二分的思路将复杂度降下来呢?二分的思路一般就是每次将数据规模降低一半,恰巧,其实为了求第 k 个位置的数,其 \frac{k-1}{2} 位置的及前方的数一定位于同一个数组,那么比较俩数组 \frac{k-1}{2} 位置的数,并将小的直接舍弃,就做到了对半降低数据量。最终如果某个数组空了,或者不需要舍弃了,即可直接返回结果。这题最难的点就是对半边界的取值,一不小心就会出现偏差,还是细致至上了。

/*
Author Owen_Q
*/
public class ArrayMedian {public static double findMedianSortedArrays(int[] nums1, int[] nums2) {int nums1Len = nums1.length;int nums2Len = nums2.length;int medianMin = (nums1Len + nums2Len - 1) / 2;int medianMax = (nums1Len + nums2Len) / 2;return ((double)getMedian(nums1, 0, nums1Len - 1, nums2, 0, nums2Len - 1, medianMin) + (double)getMedian(nums1,0, nums1Len - 1, nums2, 0, nums2Len - 1, medianMax)) / 2.0;}private static int getMedian(int[] nums1, int nums1Start, int nums1End, int[] nums2, int nums2Start, int nums2End,int pos) {if (nums1Start > nums1End) {return nums2[nums2Start + pos];}if (nums2Start > nums2End) {return nums1[nums1Start + pos];}if (pos == 0) {return Math.min(nums1[nums1Start + pos], nums2[nums2Start + pos]);}int num1pos = Math.min(nums1End, nums1Start + (pos - 1) / 2);int num2pos = Math.min(nums2End, nums2Start + (pos - 1) / 2);if (nums1[num1pos] <= nums2[num2pos]) {int newPos = pos + nums1Start - num1pos - 1;return getMedian(nums1, num1pos + 1, nums1End, nums2, nums2Start, nums2End, newPos);} else {int newPos = pos + nums2Start - num2pos - 1;return getMedian(nums1, nums1Start, nums1End, nums2, num2pos + 1, nums2End, newPos);}}
}

多想一步:拆分区间

其实上述思路是用到了log复杂度将数据量减半的思路,但其实还有一个更通用的二分方式,就是二分特定位置。

针对中位数,我们可以将数组拆分成左右两个区间,要求两个区间的元素数量完全相同,或者左侧比右侧少一个元素。并且要求左侧的数一定都小于等于右侧的数。此时,若数组大小为奇数,则右侧最小值为中位数,否则,左侧最大值和右侧最小值的平均值即为中位数。

那么问题就简化为了,如何寻找到划分区间的位置。首先,我们可以将短的数组作为操作数组,因为只要短的数组的划分位置定了,那么根据元素数量就一定能算出长的数组的划分位置。假设数组1的长度为 nums1Len,数组2的长度为 nums2Len,数组1的划分位置为 mid,那么数组2的划分位置就是 (nums1Len + nums2Len) / 2 - mid。于是我们二分短的数组的划分位置,即可得到长数组的划分位置,再检查一下是否左边最大值小于等于右边最小值即可。至于二分移动方案,若左上大于右下,则划分位置需要向左移,否则向右移。最后注意一下当划分位置移动到边界时,那么边界的数如果不存在则不参与比较,可能用个int的最大值和最小值来跳过比较即可。

/*
Author Owen_Q
*/
public class ArrayMedian {public static double findMedianSortedArraysByDivider(int[] nums1, int[] nums2) {int nums1Len = nums1.length;int nums2Len = nums2.length;if (nums1Len > nums2Len) {return findMedianSortedArraysByDivider(nums2, nums1);}int st = 0;int en = nums1Len;int medianMin = 0;int medianMax = nums1Len - 1;while (st <= en) {int mid = (st + en) / 2;int mid2 = (nums1Len + nums2Len) / 2 - mid;int left1 = mid == 0 ? Integer.MIN_VALUE : nums1[mid - 1];int left2 = mid2 == 0 ? Integer.MIN_VALUE : nums2[mid2 - 1];int right1 = mid == nums1Len ? Integer.MAX_VALUE : nums1[mid];int right2 = mid2 == nums2Len ? Integer.MAX_VALUE : nums2[mid2];medianMin = Math.max(left1, left2);medianMax = Math.min(right1, right2);if (medianMin <= medianMax) {break;} else if (left1 > right2) {en = mid - 1;} else {st = mid + 1;}}if ((nums1Len + nums2Len) % 2 == 1) {return medianMax;} else {return (double)(medianMin + medianMax) / 2.0;}}
}

最终,二分也完结撒花了

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

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

相关文章

【IDEA】格式化代码工具配置

格式化代码快捷键&#xff1a; CtrlAltL格式代码的时候不会再方法名与参数中间添加空格默认不勾选的情况下&#xff1a;代码样例&#xff1a;勾选之后的样例&#xff1a;选择不勾选&#xff0c;IDEA默认情况下就是不勾选的状态忽略加载文件有些非必要加载到开发工具中的文件我们…

驱动开发(3)|rk356x驱动GPIO基础应用之点亮led灯

点亮LED灯看似是一个基础的操作&#xff0c;但实际上&#xff0c;许多高级应用也依赖于高低电平的切换。例如&#xff0c;脉冲宽度调制&#xff08;PWM&#xff09;信号可以用来精确控制电机的转速&#xff0c;通过改变脉冲的频率和占空比&#xff0c;实现对电机的精确调节&…

手动搭建PHP环境:步步为营,解锁Web开发

目录一、引言二、准备工作2.1 明确所需软件2.2 下载软件三、Windows 系统搭建步骤3.1 安装 Apache 服务器3.2 安装 PHP3.3 集成 Apache 与 PHP3.4 安装 MySQL3.5 配置 PHP 连接 MySQL四、Linux 系统搭建步骤&#xff08;以 Ubuntu 为例&#xff09;4.1 更新系统4.2 安装 Apache…

DrissionPage:一款让网页自动化更简单的 Python 库

在网页自动化领域&#xff0c;Selenium 和 Playwright 早已是开发者耳熟能详的工具。但今天要给大家介绍一款更轻量、更易用的 Python 库 ——DrissionPage。它以 "融合 selenium 和 requests 优势" 为核心设计理念&#xff0c;既能像 requests 一样高效处理静态网页…

理解Grafana中`X-Scope-OrgID`的作用与配置

X-Scope-OrgID的作用 该HTTP Header用于标识Loki日志数据的所属租户&#xff08;组织&#xff09;。在多租户模式下&#xff0c;Loki通过此Header隔离不同团队或用户的数据&#xff0c;确保查询和存储的独立性。数据隔离&#xff1a; 租户A的日志标记为X-Scope-OrgID: team-a&a…

【PycharmPyqt designer桌面程序设计】

在 main.py 中调用 Qt Designer 生成的 windows.py&#xff08;假设它是 PySide2 版&#xff09;。 只要把两个文件放在同一目录即可直接运行。 ──────────────────── 1️⃣ windows.py&#xff08;Qt Designer 生成&#xff0c;已转码&#xff09; # -*-…

Unity Android Logcat插件 输出日志中文乱码解决

背景之前安卓真机调试看日志&#xff0c;一直用的是Android Studio自带的adb命令进行看日志&#xff0c;不太方便&#xff0c;改用Unity自带的安卓日志插件时&#xff0c;存在中文日志乱码问题。插件安装基于Unity6000.1.11版本&#xff1a;Window -> Package Management -&…

Halcon双相机单标定板标定实现拼图

1.Halcon图像拼接算法在之前的文章里也写过&#xff0c;主要是硬拼接和特征点拼接两种方式&#xff0c;今天增加另一种拼接图像的方式。应用场景是多个相机联合一起拍大尺寸的物体&#xff0c;并且相机视野之间存在重叠区域。通过在同一个标定板上面标定&#xff0c;计算两个相…

动物世界一语乾坤韵芳华 人工智能应用大学毕业论文 -仙界AI——仙盟创梦IDE

提示词在一个奇幻的童话森林里&#xff0c;所有的动物都像人类一样直立行走&#xff0c;穿着各种搞怪的衣服。 一只戴着超大眼镜、穿着背带裤的乌龟&#xff0c;正一本正经地站在一个蘑菇舞台上&#xff0c;拿着一根树枝当作麦克风&#xff0c;准备唱歌。它的眼镜总是往下滑&am…

SpringBoot(原理篇)

大家好&#xff0c;这里是 盛码笔记。 本篇我们来聊一聊 Spring Boot 的“魔法”是如何实现的。你可能已经用过 Spring Boot 快速搭建项目&#xff0c;但有没有想过&#xff1a;为什么只需要引入几个 starter&#xff0c;Spring Boot 就能自动配置好整个应用环境&#xff1f; …

数据结构:栈(区间问题)

码蹄集OJ-小码哥的栈 #include<bits/stdc.h> using namespace std; #define int long long const int N1e67; struct MOOE {int ll,rr; }; stack<MOOE>st; signed main( ) {ios::sync_with_stdio(false);cin.tie(nullptr);int n;cin>>n;while(n--){int opt…

Vue 中 data、watch、created 和 methods

以下是 Vue 中 data、watch、created 和 methods 的详细解释&#xff0c;结合常见使用场景和示例&#xff1a;1. data&#xff1a;响应式数据容器 作用&#xff1a;定义组件的响应式数据&#xff08;状态&#xff09;&#xff0c;当数据变化时&#xff0c;视图自动更新。特点&a…

精密模具冷却孔内轮廓检测方法探究 —— 激光频率梳 3D 轮廓检测

引言精密模具冷却孔的内轮廓精度直接影响注塑成型效率与制品质量。冷却孔具有深径比大&#xff08;可达 25:1&#xff09;、结构复杂&#xff08;多为螺旋形或异形&#xff09;、表面质量要求高&#xff08;Ra≤0.2μm&#xff09;等特点&#xff0c;传统检测方法难以满足其高精…

Vue单文件组件与脚手架工程化开发

一、Vue与VueComponent原型关系解析1. 原型链关系图解在Vue中&#xff0c;组件实例(VueComponent)与Vue实例之间存在特殊的原型链关系&#xff1a;VueComponent.prototype.__proto__ Vue.prototype这种设计使得所有组件都能访问Vue原型上定义的方法和属性。2. 原理验证示例// …

架构设计之计算高性能——单体服务器高性能

架构设计之计算高性能——单体服务器高性能 高性能是每个程序员共同的追求&#xff0c;无论是开发系统&#xff0c;还是仅仅只是写一段脚本&#xff0c;都希望能够达到高性能的效果&#xff0c;而高性能又是软件系统设计中最复杂的一步。无论是开发千万级并发的电商系统&#…

Unity灯光面板环境设置

在Unity中&#xff0c;环境设置&#xff08;Environment Lighting&#xff09; 是灯光面板&#xff08;Lighting Window&#xff09;的核心功能之一&#xff0c;用于控制场景的全局光照效果&#xff0c;包括天空盒、环境光、反射和雾效等。这些设置直接影响场景的整体氛围和真实…

MySQL语句优化案例

1.案例in查询条件很慢其中in中共115个select id,detail_id,request,response,utime,ctime from response_detaill where detaill_id in (26371986, 26372242, 26371984, 26371990, 26400150, 26371988, 26371994, 26371992,26371998, 26371996, 26371970, 26371968, 2637197…

能行为监测算法:低成本下的高效管理

AI监控智慧公司管理&#xff1a;降本增效的实践与突破一、背景&#xff1a;经济压力下的管理转型需求在经济下行周期&#xff0c;企业面临人力成本攀升、管理效率低下、安全风险频发等多重挑战。传统监控依赖人工巡检&#xff0c;存在响应滞后、误判率高、数据孤岛等问题&#…

当前(2024-07-14)视频插帧(VFI)方向的 SOTA 基本被三篇顶会工作占据,按“精度-速度-感知质量”三条线总结如下,供你快速定位最新范式

当前&#xff08;2024-07-14&#xff09;视频插帧&#xff08;VFI&#xff09;方向的 SOTA 基本被三篇顶会工作占据&#xff0c;按“精度-速度-感知质量”三条线总结如下&#xff0c;供你快速定位最新范式。感知质量最佳&#xff1a;CVPR 2024 ‑ PerVFI • 关键词&#xff1a;…

开源 python 应用 开发(七)数据可视化

最近有个项目需要做视觉自动化处理的工具&#xff0c;最后选用的软件为python&#xff0c;刚好这个机会进行系统学习。短时间学习&#xff0c;需要快速开发&#xff0c;所以记录要点步骤&#xff0c;防止忘记。 链接&#xff1a; 开源 python 应用 开发&#xff08;一&#xf…