[二分查找] 二:二分查找的经典例题
1.何时应该会使用二分查找
- 当题目中出现有序数组时
- 当时间复杂度要求为log(n)时
- 搜索范围可以一次缩小一半时
2. 经典例题1
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
请必须使用时间复杂度为 O(log n) 的算法。
示例 1:
输入: nums = [1,3,5,6], target = 5
输出: 2
示例 2:
输入: nums = [1,3,5,6], target = 2
输出: 1
示例 3:
输入: nums = [1,3,5,6], target = 7
输出: 4
示例 4:
输入: nums = [1,3,5,6], target = 0
输出: 0
示例 5:
输入: nums = [1], target = 0
输出: 0
此题为最经典的二分查找
int searchInsert(vector<int>& nums, int target) {int left = 0, right = nums.size();while(left < right){int mid = (left+right)/2;if(target == nums[mid]) return mid;else if(target > nums[mid]){left = mid + 1;}else {right = mid;}}return left;
}
3. 经典例题2
整数数组 nums 按升序排列,数组中的值互不相同。
在传递给函数之前,nums 在预先未知的某个下标k(0 <= k < nums.length)
上进行了 旋转,使数组变为 [nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]]
(下标 从 0 开始 计数)。
例如, [0,1,2,4,5,6,7] 在下标 3 处经旋转后可能变为 [4,5,6,7,0,1,2] 。
给你 旋转后 的数组 nums 和一个整数 target ,如果 nums 中存在这个目标值 target ,则返回它的下标,否则返回 -1 。要求时间复杂度为log(n)。
示例 1:
输入:nums = [4,5,6,7,0,1,2], target = 0
输出:4
示例 2:
输入:nums = [4,5,6,7,0,1,2], target = 3
输出:-1
示例 3:
输入:nums = [1], target = 0
输出:-1
题目要求我们的时间复杂度为log(n),所以我们很快能想到和二分查找有关。数组nums一开始为有序的,但是经过旋转之后不再整体有序,变成了两个有序的部分。
这种情况下我们每次二分先检查有序的那一半(至少有一半是有序的),如果要找的值正好在有序的这部分(比较左右边界即可判断出目标值是否在有序部分),则收缩边界,再进行二分查找。如果不在有序的部分,则再考虑无序的部分,无序的部分可以再分为两个部分,其中又有一半一定是有序的,剩下的步骤与前面一样
int search(vector<int>& nums, int target) {int left = 0, right = nums.size()-1;while(left <= right){int mid = (left+right)/2;if(nums[mid] == target) return mid;//说明mid左边有序if(nums[mid] >= nums[left]){//判断目标值是否在有序部分if(nums[mid] > target && nums[left] <= target){right = mid - 1;}else left = mid + 1;}//说明mid右边有序else{//判断目标值是否在有序部分if(nums[mid] < target && nums[right] >= target){left = mid + 1;}else right = mid - 1;}}return -1;
}
3. 经典例题3
给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。
算法的时间复杂度应该为 O(log (m+n)) 。
示例 1:
输入:nums1 = [1,3], nums2 = [2]
输出:2.00000
解释:合并数组 = [1,2,3] ,中位数 2
示例 2:
输入:nums1 = [1,2], nums2 = [3,4]
输出:2.50000
解释:合并数组 = [1,2,3,4] ,中位数 (2 + 3) / 2 = 2.5
示例 3:
输入:nums1 = [0,0], nums2 = [0,0]
输出:0.00000
示例 4:
输入:nums1 = [], nums2 = [1]
输出:1.00000
示例 5:
输入:nums1 = [2], nums2 = []
输出:2.00000
两个数组长度是固定的,所以中位数的位置也是固定的。当两数组长度之和为奇数时,中位数下标为:(totalLength + 1) / 2
,若为偶数,中位数为 (nums[totalLength / 2] + nums[(totalLength + 1) / 2])/2
要找到第 k (k>1) 小的元素,那么就取 pivot1 = nums1[k/2-1]
和 pivot2 = nums2[k/2-1]
进行比较
- 这里的 “/” 表示整除
- nums1 中小于等于 pivot1 的元素有 nums1[0 … k/2-2] 共计 k/2-1 个
- nums2 中小于等于 pivot2 的元素有 nums2[0 … k/2-2] 共计 k/2-1 个
- 取
pivot = min(pivot1, pivot2)
,两个数组中小于等于 pivot 的元素共计不会超过 (k/2-1) + (k/2-1) <= k-2 个,这样 pivot 本身最大也只能是第 k-1 小的元素 - 如果
pivot = pivot1,那么 nums1[0 .. k/2-1]
都不可能是第 k 小的元素。把这些元素全部 “删除”,剩下的作为新的 nums1 数组 - 如果
pivot = pivot2,那么 nums2[0 .. k/2-1]
都不可能是第 k 小的元素。把这些元素全部 “删除”,剩下的作为新的 nums2 数组 - 由于我们 “删除” 了一些元素(这些元素都比第 k 小的元素要小),因此需要修改 k 的值,减去删除的数的个数,搜索区间每次缩短了一半 k=k-k/2。
int getKthElement(const vector<int>& nums1, const vector<int>& nums2, int k) {int m = nums1.size(), n = nums2.size();int index1 = 0, index2 = 0;while(true){if(index1 == m){return nums2[index2 + k - 1];}else if(index2 == n){return nums1[index1 + k - 1];}else if(k == 1){return min(nums1[index1], nums2[index2]);}int newIndex1 = min(index1 + k / 2 - 1, m - 1);int newIndex2 = min(index2 + k / 2 - 1, n - 1);int pivot1 = nums1[newIndex1];int pivot2 = nums2[newIndex2];if (pivot1 <= pivot2) {k -= newIndex1 - index1 + 1;index1 = newIndex1 + 1;}else {k -= newIndex2 - index2 + 1;index2 = newIndex2 + 1;}}}double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {int totalLength = nums1.size() + nums2.size();if (totalLength % 2 == 1) {return getKthElement(nums1, nums2, (totalLength + 1) / 2);}else {return (getKthElement(nums1, nums2, totalLength / 2) + getKthElement(nums1, nums2, totalLength / 2 + 1)) / 2.0;}}
[二分查找] 二:二分查找的经典例题相关推荐
- 查找---结合力扣几道经典例题讲解
文章目录 一.查找表 考虑的基本数据结构 算法应用 LeetCode 349 Intersection Of Two Arrays 1 题目描述 分析实现 LeetCode 350 Intersect ...
- C语言之二分查找法或折半查找法剖析(经典例题,经典解析)
二分查找法(也叫折半查找法): 什么是二分查找? 具体查找的方式? 两种方法剖析 易错点列举 先举例题: int arr[]={1,2,3,4,5,6,7,8,9,10}; 找出7所在的位置. 分析之 ...
- 【基础算法】二分法(二分答案,二分查找),三分法,Dinkelbach算法,算法详解+例题剖析
目录 一 . 二分法 二分搜索得要求: 二分查找步骤: 二分答案: 玄学的二分(二分答案) 二 . 三分法 例题 三.01分数规划问题相关算法与题目讲解(二分法与Dinkelbach算法) 一 . 二 ...
- 二分查找算法详解(经典二分和左右边界查找)
目录 二分查找算法 1. 二分查找算法框架 2. 经典二分查找算法 问题1. 为什么while循环中使用<=号而不是用<号,右边区间right为什么要对数组大小减一? 问题2. 为什么 l ...
- 详解【C语言】中的二分查找法和折半查找法(例题解答)
目录 问题 思路 详解 代码 问题 在一个有序数组中查找具体的某个数字n 比如我买了一双鞋,你好奇问我多少钱,我说不超过300元.你还是好奇,你想知道到底多少,我就让你猜,你会怎么猜? 答案:你每次猜 ...
- 二分查找法和Fibonacci查找
一.简要介绍二分查找算法 二分查找算法(Binary Search)是一种非常经典且有用的查找算法,它适用于有序数组的元素查找,并且思路简单,能够用非常简洁的代码来将其实现,经典版本的二分查找算法最优 ...
- 第十九章:二分查找和二分答案
二分查找 二分的思想在程序设计中有着广泛的应用,例如,排序算法中的快速排序.归并排序,数据结构中的二叉树.堆.线段树等.二分是一种常用且高效的算法,它的基本用途是在单调序列中进行查找和判定操作. 二分 ...
- 数据结构与算法(8-2)有序表查找(折半查找(二分查找)、插值查找)
目录 一.折半查找(二分查找) 二.插值查找 总代码 一.折半查找(二分查找) 原理:一次次折半,不断向着查找值的位置靠近 . 适用场景:有序(必须) 流程:开始时,min标志首,max标志尾,med ...
- Java有序表查找:折半查找、二分查找、差值查找和斐波那契查找
Java有序表查找:折半查找.二分查找.差值查找和斐波那契查找 [尊重原创,转载请注明出处]http://blog.csdn.net/guyuealian/article/details/51 ...
最新文章
- linux命令ssh
- RocketMQ-初体验RocketMQ(11)-过滤消息_自定义Java类筛选消息
- 冲刺第一天 12.29 SAT
- 阿里云混合云的政企上云新路径
- Qt中 Qstring 与QbyteArray的互相转换
- MapReduce-流量统计求和-FlowBean和Mapper代码编写
- java中的深度克隆浅克隆_了解Java中的可克隆接口
- Java学习之String StringBuffer StringBuilder区别
- 地形图如何转换为数字高程模型(DEM)
- 物联卡的使用_物联卡在手机上使用有什么影响?网友:寿命分别是3个月,16天,9天...
- 80万辆车“云上飞驰”的背后
- IntelliJ IDEA-我的习惯性设置
- Entity Framework 5自动生成ObjectContext或者DbContext的设置
- 如何编写可移植的c/c++代码
- web页面播放实时视频流
- Vue实现简单的音乐播放器
- DOS命令行 定时关机取消定时关机
- linux cp拷贝一个文件到另一个目录,cp命令复制文件夹到另一个文件夹的注意事项 - 翟码农技术博客...
- 【历史上的今天】12 月 28 日:冯·诺伊曼诞生;林纳斯·托瓦兹出生;CSDN 正式上线
- net.sf.json
热门文章
- banner手动切换效果
- 文件中的类都不能进行设计,因此未能为该文件显示设计器。设计器检查出文件中有以下类: FormMain --- 未能加载基类...
- HDU 1564 简单博弈 水
- SectionIndexer中的getSectionForPosition()与getPositionForSection()
- Memcached源码分析
- 微软正式推免费Word 电脑商Office收费降60%
- Google Chrome 调试JS利器
- Struts2.0实现的文件上传(单附件和多附件)以及附件下载功能
- POJ 2728 最优比率生成树
- 【Android Gradle 插件】Module 目录下 build.gradle 配置文件 ( plugins 闭包代码块中引入插件 | PluginAware#apply 方法引入插件 )