二分查找及模板深度解析:right <= left 还是 right < left ? mid=left+(right-left)/2还是mid=left+(right-left +1 )/2 ?

本文涉及的产品
云解析 DNS,旗舰版 1个月
云解析DNS,个人版 1个月
全局流量管理 GTM,标准版 1个月
简介: 二分查找及模板深度解析:right <= left 还是 right < left ? mid=left+(right-left)/2还是mid=left+(right-left +1 )/2 ?

@[TOC](二分查找及模板深度解析:right <= left 还是 right < left ? mid=left+(right-left)/2还是mid=(left+right-left)/2 ?)


前言

下面博主会给出一道经典面试题进行分析,在最后会给出二分查找模板!!!

题目:

1. 解读

我们可以将题目转化为求target第一次出现的下标,以及最后一次出现的下标。然后就转换成两次二分查找了,分别查找左右边界了!

2. 二分查找左边界

大概思路已经了,下面就是判断循环条件是right <= left 还是 right < left? 以及中点求取是 mid=left+(right-left)/2还是mid=left+(right-left +1 )/2 ?

2.1 循环判断条件

在上述循环中,我们得到了左右边界移动行为:left = mid + 1right = mid

结论: 循环条件是right <= left 还是 right < left ,主要问题在于最后一步left=right是否会导致死循环。如果不会的,两者循环判断条件无所谓,任选其一即可。

2.2 中点求取

所以中点mid=left+(right-left)/2还是mid=left+(right-left +1 )/2,主要还是取决于左右下标行为在最后当数据为偶数(即2个)时是否会导致死循环。如果两种方式都不会,则两者任选其一。

但好在我们有模板,无需担心

3. 右边界

4. 最终代码

class Solution {
public:
    vector<int> searchRange(vector<int>& nums, int target) {
        if(nums.size()==0)
            return {-1, -1};
        int begin=0;//记录查找元素的第一个
        int left=0, right=nums.size()-1;
        while(left<right)
        {
            int mid=left+(right-left)/2;
            if(nums[mid] < target)
                left=mid+1;
            else
                right=mid;
        }
        //判断是否存在结果
        if(nums[left] != target)
            return {-1,-1};
        else    
            begin=left;
        
        //一定存在结果,查找最后一个元素
        left=0, right=nums.size()-1;
        while(left<right)
        {
            int mid=left+(right-left+1)/2;
            if(nums[mid] > target)
                right=mid-1;
            else
                left=mid;
        }
        return {begin, left};
    }
};

5. 模板

模板一:三段式(最普通)

由于上述情况时过于简单,博主就不介绍了。

模板二:⼆段式

请⼤家⼀定不要觉得背下模板就能解决所有⼆分问题。⼆分问题最重要的就是要分析题意,然后确定要搜索的区间,根据分析问题来写出⼆分查找算法的代码。

要分析题意,确定搜索区间,不要死记模板,不要看左闭右开什么乱七⼋糟的题解

模板记忆技巧:

  1. 关于什么时候⽤三段式,还是⼆段式中的某⼀个,⼀定不要强⾏去⽤,⽽是通过具体的问题分析情况,根据查找区间的变化确定指针的转移过程,从⽽选择⼀个模板。
  2. 当选择两段式的模板时:
    ◦ 在求 mid 的时候,只有 right - 1 的情况下,才会向上取整(也就是 +1 取中间数)


相关文章
|
28天前
|
SQL 自然语言处理 前端开发
【JavaScript】ECMAS6(ES6)新特性概览(一):变量声明let与const、箭头函数、模板字面量全面解析
【JavaScript】ECMAS6(ES6)新特性概览(一):变量声明let与const、箭头函数、模板字面量全面解析
18 2
|
1月前
|
SQL 算法 数据挖掘
深入解析力扣183题:从不订购的客户(LEFT JOIN与子查询方法详解)
深入解析力扣183题:从不订购的客户(LEFT JOIN与子查询方法详解)
|
2月前
|
C++
【期末不挂科-C++考前速过系列P6】大二C++实验作业-模板(4道代码题)【解析,注释】
【期末不挂科-C++考前速过系列P6】大二C++实验作业-模板(4道代码题)【解析,注释】
【期末不挂科-C++考前速过系列P6】大二C++实验作业-模板(4道代码题)【解析,注释】
|
2月前
|
程序员 编译器 C++
C++中的模板与泛型编程技术深度解析
C++中的模板与泛型编程技术深度解析
|
29天前
|
SQL 自然语言处理 JavaScript
【JavaScript】ECMAS6(ES6)新特性概览(一):变量声明let与const、箭头函数、模板字面量全面解析
ES6,作为ECMAScript 2015的简称,标志着JavaScript编程语言的一个重要进化节点。它不是渐进的变化,而是一次飞跃式的更新,为开发者带来了一系列强大的新特性与语法糖,极大提升了代码的简洁性、可读性和运行效率。从新的变量声明方式let与const,到优雅的箭头函数、模板字符串,再到让对象操作更为灵活的解构赋值与增强的对象字面量,ES6的每项改进都旨在让JavaScript适应日益复杂的应用场景,同时保持其作为脚本语言的活力与魅力。本文是深入探索这些核心特性的起点,为你铺开一条通向高效、现代JavaScript编程实践
35 0
|
2月前
|
SQL 缓存 JavaScript
深入解析JavaScript中的模板字符串
深入解析JavaScript中的模板字符串
25 1
|
2月前
项目管理工具计划模板解析:项目管理工具的双重功能与创建方法
本文介绍了项目计划模板的含义和重要性。项目计划模板是用于规划项目结构的可编辑文档,帮助团队明确任务、分配责任和管理时间。模板有助于跟踪项目进度、避免任务冲突,并简化会议安排。创建模板通常涉及选择合适的项目管理工具,如Zoho Projects或Microsoft Excel,然后分解任务、定义日期并持续调整。在Zoho Projects中,用户可以按步骤创建模板,包括命名、添加任务和设置相关细节。
35 0
|
2月前
|
存储 程序员 编译器
【C++ 模板类与虚函数】解析C++中的多态与泛型
【C++ 模板类与虚函数】解析C++中的多态与泛型
83 0
|
2月前
|
JSON C++ 数据格式
【C++ 泛型编程 进阶篇】深入解析C++中的std::conditional_t与std::void_t:模板编程的神器
【C++ 泛型编程 进阶篇】深入解析C++中的std::conditional_t与std::void_t:模板编程的神器
125 0
|
26天前
|
XML Java 数据格式
深度解析 Spring 源码:从 BeanDefinition 源码探索 Bean 的本质
深度解析 Spring 源码:从 BeanDefinition 源码探索 Bean 的本质
28 3

推荐镜像

更多