【算法】二分法 ② ( 排序数组中查找目标值 | 二分法的经典写法 | 在排序数组中查找元素的最后一个位置 | 二分法的通用模板 )
创始人
2024-05-20 07:34:04
0

文章目录

  • 一、排序数组中查找目标值 ( 二分法的经典写法 )
  • 二、在排序数组中查找元素的最后一个位置 ( 二分法的通用模板 )





一、排序数组中查找目标值 ( 二分法的经典写法 )



https://leetcode.cn/problems/binary-search/

典型的二分查找题目 : 从一个 有序数组 中查找某个 目标值 , 返回 该目标元素在数组中的索引值 , 如果 数组中没有该 目标值 , 则返回 -1 ;

如 : 从 [1 , 2 , 4 , 5 , 6] 中查找 目标值 2 , 返回 2 对应的数组元素索引 为 1 ; 如果从上述数组中查找 3 , 数组中没有该元素 , 则返回 -1 ;


二分法的经典实现 :

public class Solution {public int search(int[] nums, int target) {// 1. 判断参数合法性if(nums == null || nums.length == 0) {return -1;}// 2. 二分查找的范围int start = 0, end = nums.length - 1;// 3. 开始循环进行二分查找while(start <= end) {// 3.1 计算中间索引int mid = start + (end - start) / 2;// 3.2 对比中间元素与目标值if(nums[mid] == target) {// 如果 中心元素 = 目标值 , 找到了目标元素 , 直接返回该索引值return mid;} else if(nums[mid] > target) {// 如果 中心元素 > 目标值 , 则需要去 该查找区间的 左侧继续查找end = mid - 1;} else {// 如果 中心元素 < 目标值 , 则需要去 该查找区间的 右侧继续查找start = mid + 1;}}// 4. 循环完毕 , 说明最终 start > end , 没有找到目标值return -1;}
}

上述二分法实现 , 处理 数值没有重复的 数组查找目标值 是可实现的 ;

如果遇到 数组中 要查找的值是重复的 , 要求返回这些数值中的某个指定的索引 , 如 : 返回最后一个 , 返回第一个 , 返回第 n 个 , 等附加要求时 , 上述二分法就无法实现了 ;





二、在排序数组中查找元素的最后一个位置 ( 二分法的通用模板 )



在排序数组中查找元素的最后一个位置 : 从一个 有序数组 中查找某个 目标值 , 返回 该目标元素在数组中的索引值 , 该有序数组中的 元素 可以重复 ,

  • 如果 数组中没有该 目标值 , 则返回 -1 ;
  • 你必须设计并实现 时间复杂度为 O(log n) 的算法解决此问题。

如 : 从 [1 , 2 , 2 , 4 , 5 , 6] 中查找 目标值 2 , 返回 2 对应的数组元素索引 为 1 和 2 , 这里查找的是最后一个位置 , 结果为 2 ; 如果从上述数组中查找 3 , 数组中没有该元素 , 则返回 -1 ;


上述题目要求 时间复杂度 为 O(log⁡n)O(\log n)O(logn) , 在上一篇博客 【算法】二分法 ① ( 二分法基本原理简介 | 二分法与哈希表对比 | 常见算法对应的时间复杂度 ) 中提到了常见的算法的时间复杂度如下 , 时间复杂度从小到大进行排序为 :

  • O(1)O(1)O(1) : 位运算 , 哈希表查询
  • O(log⁡n)O(\log n)O(logn) : 二分法 , 快速幂算法 , 辗转相除法 , 倍增法 ;
  • O(n)O(n)O(n) : 枚举法 , 单调栈算法 , 双指针算法 ;
  • O(nlog⁡n)O(n \log n)O(nlogn) : 快速排序 , 归并排序 , 堆排序 ;
  • O(n2)O(n^2)O(n2) : 枚举法 , 动态规划 ;
  • O(n3)O(n^3)O(n3) : 枚举法 , 动态规划 ;
  • O(2n)O(2^n)O(2n) : 组合相关的搜索问题 ;
  • O(n!)O(n!)O(n!) : 排列相关的搜索问题 ;

显然 , 这里需要选择 二分法解决上述算法问题 ;


代码示例 :

package cn.zkhw.schedule.utils;public class Solution {public int search(int[] nums, int target) {// 1. 判断参数合法性if(nums == null || nums.length == 0) {return -1;}// 2. 二分查找的范围int start = 0, end = nums.length - 1;// 3. 开始循环进行二分查找// 此处注意 start 和 end 区间需要能覆盖住所有目标值// 该循环条件很重要 , 是通用模板// ★ 要点一 : 此处尽量不要使用 start <= end 或 start < end 作为循环判定条件 , 在某些情况下会执行失败// 为了让程序有更多的适应性 , 这里使用 start + 1 < end 作为循环判定条件 , 可以有效避免死循环while(start + 1 < end) {// 3.1 计算中间索引// ★ 要点二 : 此处尽量不要使用 (start + end) / 2 , 如果 两个数值都接近 Int.MAX_VALUE 则会溢出int mid = start + (end - start) / 2;// 3.2 对比中间元素与目标值if(nums[mid] == target) {// 如果 中心元素 = 目标值 , 找到了目标元素的第一个位置end = mid;} else if(nums[mid] > target) {// 如果 中心元素 > 目标值 , 则需要去 该查找区间的 左侧继续查找// ★ 要点三 : 由于循环判定条件是 start + 1 < end , 此处 end 赋值可以不使用 mid - 1end = mid;} else {// 如果 中心元素 < 目标值 , 则需要去 该查找区间的 右侧继续查找// ★ 要点四 : 由于循环判定条件是 start + 1 < end , 此处 start 赋值可以不使用 mid + 1start = mid;}}// 4. ★ 要点五 : 循环完毕 , 判定 start 和 end 是不是要找的值// 如果数组只有两个数的情况下 // while(start + 1 < end) 循环控制条件中的 start + 1 < end 直接为 false // 循环直接退出 , 此处判定一下 start 和 end 是不是要找的值 if(nums[start] == target) {return -1;}if(nums[end] == target) {return -1;}// 5. 没有找到目标值return -1;}
}

相关内容

热门资讯

【NI Multisim 14...   目录 序言 一、工具栏 🍊1.“标准”工具栏 🍊 2.视图工具...
银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...
AWSECS:访问外部网络时出... 如果您在AWS ECS中部署了应用程序,并且该应用程序需要访问外部网络,但是无法正常访问,可能是因为...
Android|无法访问或保存... 这个问题可能是由于权限设置不正确导致的。您需要在应用程序清单文件中添加以下代码来请求适当的权限:此外...
北信源内网安全管理卸载 北信源内网安全管理是一款网络安全管理软件,主要用于保护内网安全。在日常使用过程中,卸载该软件是一种常...
AWSElasticBeans... 在Dockerfile中手动配置nginx反向代理。例如,在Dockerfile中添加以下代码:FR...
AsusVivobook无法开... 首先,我们可以尝试重置BIOS(Basic Input/Output System)来解决这个问题。...
ASM贪吃蛇游戏-解决错误的问... 要解决ASM贪吃蛇游戏中的错误问题,你可以按照以下步骤进行:首先,确定错误的具体表现和问题所在。在贪...
月入8000+的steam搬砖... 大家好,我是阿阳 今天要给大家介绍的是 steam 游戏搬砖项目,目前...