leetcode 经典二分查找算法题目(思路、方法、code)

算法提升:并查集的十个经典题目 算法成神之路:并查集的十个经典题目 阅读详情

leetcode 经典二分查找算法题目(思路、方法、code)

35. 搜索插入位置

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。

你可以假设数组中无重复元素。

示例 1:
输入: [1,3,5,6], 5
输出: 2
    
示例 2:
输入: [1,3,5,6], 2
输出: 1

分析:由于数组是一个有序数组,故可以采用二分搜索找位置,可以在 O ( l o g n ) O(logn) O(logn) 的时间复杂度内找到。

  • 若target在数组中出现,则典型的二分查找方法即可
  • 若target在数组中没有出现
    • 若target<nums[mid] && target>nums[mid-1] ,说明返回的下标应该是 mid
    • 若target>nums[mid] && target<nums[mid+1], 说明返回的下标应该是mid+1
    • 若mid==0 || mid==size-1 ,也就是说target应该的位置在于数组外
      • 若target<nums[0],返回0
      • 若target>nums[size-1],返回size
//暴力的方法:
class Solution {
public:
    int searchInsert(vector<int>& nums, int target) 
    {
        for(int i=0;i<nums.size();i++)
        {
            if(nums[i]>=target)
                return i;
        }
        return nums.size();
    }
};
//二分查找的方法:
class Solution {
public:
    int searchInsert(vector<int>& nums, int target) 
    {
       int index=-1;
       int begin=0,end=nums.size()-1;
       while(index==-1) //未找到位置
       {
           int mid=(begin+end)/2;
           if(target==nums[mid])
                index=mid;
           else if(target<nums[mid])  //mid处值大于target
           {
               if(mid==0||target>nums[mid-1]) //短路,不用判断mid-1非法
                    index=mid;   //确定了target的位置
               end=mid-1; //因为已经判断过mid的位置,直接mid-1即可
           }
           else if(target>nums[mid])
           {
               if(mid==nums.size()-1||target<nums[mid+1])
                        index=mid+1;
                begin=mid+1;
           }
       }
       return index;
    }
};
69. x 的平方根

实现 int sqrt(int x) 函数。

计算并返回 x 的平方根,其中 x 是非负整数。

由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。

示例 1:
输入: 4
输出: 2

示例 2:
输入: 8
输出: 2
说明: 8 的平方根是 2.82842..., 
     由于返回类型是整数,小数部分将被舍去。

分析:x的平方根,在此处是指最大的满足 r*r<=x的r值,故可以用二分查找,因为该值一定在0~x间,故可以逐步判断每次减少一半区间,在 O ( l o g n ) O(logn) O(logn) 的时间复杂度内找到其应该在的位置

class Solution {
public:
    int mySqrt(int x) 
    {
        int left = 0, right = x, ans = -1;
        while (left <= right) 
        {
            int mid = (left+right)/ 2;
            if ((long long)mid * mid <= x)  //避免溢出
            {
                ans = mid;
                left = mid + 1;
            }
            else 
            {
                right = mid - 1;
            }
        }
        return ans;
    }
};
34. 在排序数组中查找元素的第一个和最后一个位置

给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。

你的算法时间复杂度必须是 O(log n) 级别。

如果数组中不存在目标值,返回 [-1, -1]。

示例 1:
输入: nums = [5,7,7,8,8,10], target = 8
输出: [3,4]
示例 2:
输入: nums = [5,7,7,8,8,10], target = 6
输出: [-1,-1]

分析:实际上,要找的位置,可以这样理解:如果target没有出现,则返回[-1,-1],否则,返回target的最左索引和target的最右索引。由于数组是排序的,因此采用二分查找,思路如下:

  • 首先利用二分查找最左索引,最左索引的特征是该坐标左侧应当不是该值,该坐标处是该值
  • 然后同样方法查找最右索引,最右索引的特征是该坐标右侧不是该值,该坐标处是该值
  • 返回即可
class Solution {
public:
    int left_bound(vector<int> & nums,int target)
    {
        int begin=0,end=nums.size()-1;
        while(begin<=end)
        {
            int mid=(begin+end)/2;
            if(target==nums[mid]) //相等时候还要找到最左侧的该值
            {
                if(mid==0||nums[mid-1]<target) //说明是最左的索引了
                    return mid;
                end=mid-1; //否则令end左移
            }
            else if(target<nums[mid])
                end=mid-1;
            else if(target>nums[mid])
                begin=mid+1;
        }
        return -1;
    }
    int right_bound(vector<int> & nums,int target)
    {
        int begin=0,end=nums.size()-1;
        while(begin<=end)
        {
            int mid=(begin+end)/2;
            if(target==nums[mid]) //相等时候还要找到最右侧的该值
            {
                if(mid==nums.size()-1||nums[mid+1]>target) //说明是最右的索引了
                    return mid;
                begin=mid+1; //否则令end左移
            }
            else if(target<nums[mid])
                end=mid-1;
            else if(target>nums[mid])
                begin=mid+1;
        }
        return -1;
    }

    vector<int> searchRange(vector<int>& nums, int target) 
    {
        vector<int> result;
        int left=left_bound(nums,target);
        int right=0;
        if(left==-1)
            right=-1;
        else
            right=right_bound(nums,target);
        result.push_back(left);
        result.push_back(right);
        return result;

    }
};
154. 寻找旋转排序数组中的最小值 II

假设按照升序排序的数组在预先未知的某个点上进行了旋转。

( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。

请找出其中最小的元素。

注意数组中可能存在重复的元素。

示例 1:
输入: [1,3,5]
输出: 1
示例 2:
输入: [2,2,2,0,1]
输出: 0

分析:原始数组为一个非递减排序,因此,我们旋转后,可知该数组应当是两个非递减序列组成,并且右侧序列的最右端(即最大值)一定不大于左侧序列的最左端(即最小值)

可以举一个具体例子来分析

给定数组  1,2,3,4,5
旋转后可以为  3,4,5,1,2
因此可以看出   3,4,5    1,2 分别是非递减序列

因此根据该性质,易知可用二分查找

  • 找到区域边界两个位置 i i i, j j j
  • 如果 左<右 ,很显然数组没有发生旋转,否则一定是左<=右
  • 找到中间位置 m i d mid mid
    • 如果中间位置的值小于右侧,说明最小值在右侧,令 i = m i d + 1 i=mid+1 i=mid+1 ,返回最初循环
    • 如果中间位置的值大于右侧,说明最小值在左侧,令 j = m i d − 1 j=mid-1 j=mid−1 ,返回最初循环
    • 如果中间位置的值等于右侧,则没办法确定最小值的位置,此时令 i i i++ 继续推进循环即可
  • 直至i=j,即找到最小值
class Solution {
public:
    int findMin(vector<int>& nums) 
    {
        int size=nums.size();
        int i=0,j=size-1;
        while(i<j)
        {
   		    if(nums[i]<nums[j]) //说明数组没有旋转 
		         return nums[i];
		    int mid=(i+j)>>1;
		    if(nums[mid]>nums[j])
		    {
			    i=mid+1;continue;  //注意这里i=mid+1 
		    }
		    if(nums[mid]<nums[j])	
		    {
			    j=mid;           //j=mid  主要是让i和j必须保持相近,避免二者相邻时出现死循环 
			    continue;
		    }
		    if(nums[mid]==nums[j])//两个值相等的话没办法二分,只能逐步右移
		    {
			    i++;
		    }
        }
        return nums[i];
    }
};
33. 搜索旋转排序数组

假设按照升序排序的数组在预先未知的某个点上进行了旋转。

( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。

搜索一个给定的目标值,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。

你可以假设数组中不存在重复的元素。

你的算法时间复杂度必须是 O(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

分析:为了达到 O ( l o g n ) O(logn) O(logn) 的时间复杂度,因此需要采用二分查找。该题采用二分查找时需要注意的是,每次找到中点后,不应该直接去比较中点与target的值,而应该首先确定左右两个区间是否是完全递增的。完全递增的区间和两个分别递增的区间的判断方式不一样。

  • 每次找到中点位置
  • 如果target等于中点处的值,返回即可
  • 如果target小于中点处的值
    • 如果左侧是递增区间
      • target>=nums[begin] ,则在[begin,mid-1]中查找
      • 否则在[mid+1,end]中查找
    • 如果左侧是旋转区间
      • 因为target小于中点处的值,故一定在旋转区间,在[begin,mid-1]中查找
  • 如果target大于中点处的值
    • 如果左侧是递增区间,
      • 则直接在[mid+1,end]中查找
    • 如果左侧是旋转区间
      • 如果target>=nums[begin],则在[begin,mid-1]中查找
      • 否则在[mid+1,end]中查找
class Solution {
public:
    int search(vector<int>& nums, int target) 
    {
        int begin=0,end=nums.size()-1;
        while(begin<=end)
        {
            int mid=(begin+end)/2;
            if(target==nums[mid])
                return mid;
            else if(target<nums[mid])
            {
                if(nums[begin]<nums[mid])//左侧递增
                {
                    if(target>=nums[begin])
                        end=mid-1;
                    else
                        begin=mid+1;
                }
                else if(nums[begin]>nums[mid])//左侧旋转
                {
                    end=mid-1;
                }
                else if(nums[begin]==nums[mid]) //只剩下两个元素
                {
                    begin=mid+1;
                }
            }
            else if(target>nums[mid])
            {
                if(nums[begin]<nums[mid])//左侧递增
                {
                    begin=mid+1;
                }
                else if(nums[begin]>nums[mid]) //左侧旋转
                {
                    if(target>=nums[begin])
                        end=mid-1;
                    else
                        begin=mid+1;
                }
                else if(nums[begin]==nums[mid]) //只剩两个元素
                    begin=mid+1;
            }
        }
        return -1;    
    }
};
详解二分查找的两种写法以及二分查找的六种变形 本文详解了二分查找的两种写法以及二分查找的六种变形。 阅读详情

相关推荐

leetcode 经典动态规划DP算法题目(思路、方法、code)

leetcode 经典动态规划DP算法题目(思路、方法、code) 动态规划最重要的在于设计DP数组,找到相应的动态转移方程 文章目录leetcode 经典动态规划DP算法题目(思路、方法、code)[70. 爬楼梯](https://leetcode-cn.com/problems/climbing-stairs/)[198. 打家劫舍](https://leetcode-cn.com/problems/house-robber/)[213. 打家劫舍 II](https://leetcode-cn.co

Ding 的博客 3483

leetcode刷题记录——二分查找(入门)

二分查找入门

GZW18620285024的博客 614

leetcode 经典栈相关题目(思路、方法、code)

用于回顾数据结构与算法时刷题的一些经验记录 栈的题目还是稍微有些难度的 文章目录[20. 有效的括号](https://leetcode-cn.com/problems/valid-parentheses/)[155. 最小栈](https://leetcode-cn.com/problems/min-stack/)[946. 验证栈序列](https://leetcode-cn.com/prob...

Ding 的博客 1454

【剑指offer】——二分查找相关例题总结

一、旋转数组的最小值 二、在排序数组中查找数字 题目一:数字在排序数组中出现的次数 题目二:0~n-1中缺失的数字 题目三:数组中数值和下标相等的元素

qq_43412060的博客 3941

leetcode 经典宽搜BFS深搜DFS题目(思路、方法、code)

leetcode 经典宽搜BFS深搜DFS题目(思路、方法、code) BFS和DFS的经典应用就是在树和图中的遍历。 地图的搜索问题通常都可以用BFS和DFS解决,下面题目非常典型,并且很多题目类似,自己如果能够独立完成基本就掌握了BFS和DFS以及地图的遍历问题。 文章目录leetcode 经典宽搜BFS深搜DFS题目(思路、方法、code)[200. 岛屿数量](https://leetcode-cn.com/problems/number-of-islands/)[127. 单词接龙](https:

Ding 的博客 2133

leetcode经典链表相关题目(思路、方法、code)

用于回顾数据结构与算法时刷题的一些经验记录 (链表题目最好自己动手画一画,可以较为清晰地知道指针的处理) 文章目录[206. 反转链表](https://leetcode-cn.com/problems/reverse-linked-list/)[92. 反转链表 II](https://leetcode-cn.com/problems/reverse-linked-list-ii/)160. [...

Ding 的博客 773

【LeetCode】二分查找精选10题

LeetCode 二分查找精选10题 详解

Qiuhan_909的博客 7375

leetcode二叉搜索树经典题目(思路、方法、code)

文章目录二叉搜索树的简介[98. 验证二叉搜索树](https://leetcode-cn.com/problems/validate-binary-search-tree/)[700. 二叉搜索树中的搜索](https://leetcode-cn.com/problems/search-in-a-binary-search-tree/)[701. 二叉搜索树中的插入操作](https://leetcode-cn.com/problems/insert-into-a-binary-search-tree/)

Ding 的博客 1426

leetcode 经典贪心算法题目(思路、方法、code)

用于回顾数据结构与算法时刷题的一些经验记录 (提出对应的贪心算法时最好自己举例子试试能否可行) 文章目录[455. 分发饼干](https://leetcode-cn.com/problems/assign-cookies/)[376. 摆动序列](https://leetcode-cn.com/problems/wiggle-subsequence/)[402. 移掉K位数字](https://...

Ding 的博客 4414

LeetCode 面试经典 150 题回顾

最经典 150 题,掌握面试所有知识点 面试经典 150 题 : 题目分析、解题思路、复杂度分析、代码展示

曾经“等你生日那天”都遥远得像未来,如今却可欢愉的挥手说“下个十年见” 8万+

1104全部报表版本号-银监会报表

G4B_Ⅲ(a)X1《与非中央交易对手的衍生具交易对手信用风险违约风险计算表(现期风险暴露法)(第一档)》G4B_Ⅲ(b)X1《与非中央交易对手的证券融资交易对手信用风险违约风险计算表(权重法)(第一档)》G4B_Ⅲ(a1)X2《与非中央交易对手的衍生具交易对手信用风险违约风险计算表(标准法)(第二档)》Ⅲ(a)X2《与非中央交易对手的衍生具交易对手信用风险违约风险计算表(现期风险暴露法)(第二档)》Ⅲ(a1)X1《与非中央交易对手的衍生具交易对手信用风险违约风险计算表(标准法)(第一档)》

数字化老司机 6297

LeetCode 力扣算法题解汇总,All in One

我刷过的所有 leetcode 算法题解的汇总。 题目的排列顺序是按照先Easy再Medium再Hard排列的,暂时还没有把题目全部整理完成。后序我会把刷过的所有的题目都整理到这个文档里。 如果想看我全部的力扣算法题解,可以看我的题解博客:[fuxuemingzhu.cn](fuxuemingzhu.cn)

负雪明烛 1万+

解决nfs挂载根文件系统报错:VFS: Unable to mount root fs via NFS, trying floppy.

解决nfs挂载根文件系统报错的问题:VFS: Unable to mount root fs via NFS, trying floppy.

汉尼拔勇闯天涯 4575

leetcode 经典回溯算法题目(思路、方法、code)

用于回顾数据结构与算法时刷题的一些经验记录 回溯与递归都要注意剪枝,避免重复计算 回溯的问题,一定要把整个树图画出来,然后再去考虑如何缩小问题,还要注意恢复状态 回溯算法的大致模板: 根据这个模板,然后根据自己画出的树图,基本所有回溯问题都可以搞定。 void backtrack(已经做的选择, 选择列表): if 当前达到了结束位置: result.pus...

Ding 的博客 2561

学习STM32的无人机控制

下面是一个基于STM32的无人机控制的简单示例代码,包括四旋翼的PID控制、遥控器信号解析和电机控制。本示例以STM32F103系列为例,使用Keil C编译器进行开发。

qq_67153941的博客 706

YOLOv8【第四章:注意力机制篇·第20节】一文讲透,注意力机制设计原则与选择指南 - 从原理到实践的系统化方法论!

🏆 本文收录于 《YOLOv8实战:从入门到深度优化》,该专栏持续复现网络上各种热门内容(全网YOLO改进最全最新的专栏,质量分97分+,全网顶流),改进内容支持(分类、检测、分割、追踪、关键点、OBB检测)。且专栏会随订阅人数上升而涨价(毕竟不断更新),当前性价比极高,有一定的参考&学习价值,部分内容会基于现有的国内外顶尖人工智能AIGC等AI大模型技术总结改进而来,嘎嘎硬核。    ✨ 特惠福利:目前活动一折秒杀价!一次订阅,永久免费,所有后续更新内容均免费阅读!

**My Coding Family** 897

leetcode 经典二叉树算法题目(思路、方法、code)

leetcode 经典二叉树算法题目(思路、方法、code) 二叉树相关题目,主要就是要搞定二叉树的多种遍历方式,包括先序遍历,中序遍历,后序遍历,层次遍历,DFS遍历。掌握了所有的遍历方法,二叉树的题目基本就化简为一些简单问题去解决。 二叉树由于其良好的结构,很多题目都可以化为递归去解决。 文章目录leetcode 经典二叉树算法题目(思路、方法、code)[226. 翻转二叉树](https://leetcode-cn.com/problems/invert-binary-tree/)[112. 路径总

Ding 的博客 1071

PyTorch深度学习实战(7)——批大小对神经网络训练的影响

在神经网络中,批( batch )是指一次输入网络进行训练或推断的一组样本。批处理( batch processing )是指将这一组样本同时输入网络进行计算的操作。本节中首先介绍批( Batch )的基本概念,并且介绍批大小在神经网络训练过程中的影响。

盼小辉丶的博客 1万+

leetcode 经典 图相关题目(思路、方法、code)

图的问题基本就是 BFS和DFS,还有拓扑排序、最短路、最小生成树,有时也会用并查集进行分类,还要注意节点的入度出度等特征。 文章目录[207. 课程表](https://leetcode-cn.com/problems/course-schedule/)[210. 课程表 II](https://leetcode-cn.com/problems/course-schedule-ii/)[684. 冗余连接](https://leetcode-cn.com/problems/redundant-connec

Ding 的博客 3135

Google Earth Engine 红树林制图方法的代码(三个模块)

谷歌地球引擎红树林制图方法(GEM)提供了一种直观、易用且可复制的工具,适用于广泛的非专业沿海管理者和决策者。该工具全面回顾并整合了相关的红树林遥感文献,并利用云计算的力量,包括简化的基于图像的潮汐校准方法。GEM 可免费用于非营利用途,并在 GEE 中运行,包含全面且详细注释的代码。GEM 专门设计用于绘制全球范围内多日期红树林分布并量化其动态变化。目前可用的工具和方法未能充分利用沿海管理者通常持有的丰富地方专业知识——GEM 致力于填补这一空白,帮助结合地方专业知识与 GEE 的云计算能力。

此星光明博客 560

PhotovoltaicPanelCleanlinessDetector:基于YOLOv8的光伏板清洁状态监测系统

data.yamlyaml复制编辑names:0: clean1: dust3: leaves4: shadow✅ 高精度污染识别✅ 具备实时检测与UI展示✅ 可本地化部署应用未来方向增加污染程度分级(轻度、中度、严重)加入时间序列分析(污染变化趋势预测)无人机集成巡检模块。

YOLO 276

leetcode经典堆相关题目(思路、方法、code)

用于回顾数据结构与算法时刷题的一些经验记录 堆的题目大多还是较为复杂的 文章目录[215. 数组中的第K个最大元素](https://leetcode-cn.com/problems/kth-largest-element-in-an-array/)[347. 前 K 个高频元素](https://leetcode-cn.com/problems/top-k-frequent-elements/)...

Ding 的博客 2014

【软件系统架构】系列六:MBSE(基于模型的系统工程)

基于模型的系统工程(MBSE)是一种以模型为核心的系统工程方法论,通过结构化、可视化的模型取代传统文档,实现从需求到验证的全生命周期管理。MBSE采用SysML建模语言,包含需求、功能、架构和验证四大要素,支持自动追踪、仿真分析和代码生成。相比文档式工程,MBSE具有变更影响自动分析、跨团队协作和高可视化等优势,广泛应用于航空航天、汽车电子等领域。典型开发流程包括需求建模、行为建模、架构建模等阶段,配合MagicDraw、Cameo等工具链实现。MBSE正与数字孪生、AI技术融合,推动自动化建模和智能验证的

moton2017的博客 2784

【二分查找】--- 进阶题目赏析

二分过程:参考代码: 🏠 寻找旋转排序数组中的最小值 📌 题目内容 二分流程:参考代码: 思考:我们划分两端区间是以D为参考点,那么我们是否能以A为参考点呢? 🏠 0~n-1中缺失的数字 📒 思路二:直接遍历找结果 📒 思路三:位运算 📒 思路四:高斯求和公式 📒 思路五:二分查找 前面的思路都很简单,但时间复杂度都是O(N)。仔细观察我们发现因为缺失了数字,会造成二段性。参考代码:

2301_79448270的博客 1703

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

leetcode 经典哈希表与字符串题目(思路、方法、code)

文章目录[409. 最长回文串](https://leetcode-cn.com/problems/longest-palindrome/)[290. 单词规律](https://leetcode-cn.com/problems/word-pattern/)[205. 同构字符串](https://leetcode-cn.com/problems/isomorphic-strings/)[49. 字母异位词分组](https://leetcode-cn.com/problems/group-anagrams

Ding 的博客 874

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

【GitHub项目推荐--LeetCodeAnimation:用动画的形式呈现LeetCode题目思路】

​​ 是一个创新的开源项目,由MisterBooo(吴师兄)创建,致力于用动画的形式演示LeetCode题目的解题思路。该项目通过直观的动画可视化,帮助开发者更好地理解和掌握算法和数据结构的核心概念,让抽象的算法变得生动易懂。🔗 ​GitHub地址🚀 ​核心价值​:动画演示 · 算法可视化 · 学习辅助 · 直观理解​项目背景​:​学习痛点​:解决算法学习抽象难懂的问题​视觉学习​:利用动画提升学习效果和理解深度​创新教学​:创新的算法教学方法​长期规划​:3-4年完成所有题目动画化​。

j8267643的博客 1060

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

上一篇: Trie树(字典树)相关概念以及实现和练习
下一篇: C++基础知识面试必备、复习细节 (2)
coding丁
博客等级 码龄9年 383粉丝 147原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值