首页 > 编程语言 >leetcode刷题--算法入门第一天--二分查找

leetcode刷题--算法入门第一天--二分查找

时间:2023-01-10 21:24:37浏览次数:53  
标签:right -- mid int 版本 区间 刷题 leetcode left

二分查找

原理

二分查找算法的原理如下:

     1. 设置查找区间:low = 0;high= n;
     2. 若查找区间[low, high]不存在,则查找失败;否则转步骤3
     3. 取中间位mid = (low + high) / 2;比较 target 与 arr[mid],有以下三种情况:
       3.1 若 target < arr[mid],则high = mid - 1;查找在左半区间进行,转步骤2;
       3.2 若 target > arr[mid],则low = mid + 1;查找在右半区间进行,转步骤2;

例题

例一

给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target  ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。
基本和最原始的情况相同,简单的把算法原理转化为代码

public:
    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;
            }
            if(nums[mid]<target)
            {
                left=mid+1;
            }
            else if(nums[mid]>target)
            {
                right=mid-1;
            }
        }
        return -1;
    }
};

例二

你是产品经理,目前正在带领一个团队开发新的产品。不幸的是,你的产品的最新版本没有通过质量检测。由于每个版本都是基于之前的版本开发的,所以错误的版本之后的所有版本都是错的。

假设你有 n 个版本 [1, 2, ..., n],你想找出导致之后所有版本出错的第一个错误的版本。

你可以通过调用 bool isBadVersion(version) 接口来判断版本号 version 是否在单元测试中出错。实现一个函数来查找第一个错误的版本。你应该尽量减少对调用 API 的次数。
示例 1:

  输入:n = 5, bad = 4
  输出:4
  解释:
  调用 isBadVersion(3) -> false 
  调用 isBadVersion(5) -> true 
  调用 isBadVersion(4) -> true
  所以,4 是第一个错误的版本。
 来源:力扣(LeetCode)
 链接:https://leetcode.cn/problems/first-bad-version
 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

此题的情况是无法通过大小的比较来缩小的区间的范围,我的想法是利用mid左右元素的是否一致来判别是否找到第一个错误元素

  • 若左右元素不同

若mid为错误版本,则mid为第一个错误版本
若mid为正确版本,则mid+1为第一个错误版本

  • 若左右元素相同

若mid为错误版本,则第一个错误版本在左侧,令right=mid-1
mid为正确版本,则第一个错误版本在右侧,令left=mid+1

代码如下:

class Solution {
public:
    int firstBadVersion(int n) {
        long left=1;
        long right=n;
        bool p,q,r;
        while(left<=right)
        {
            long mid=(left+right)/2;
            p=isBadVersion(mid-1);//用p,q,r分别记录isBadVersion(mid-1),isBadVersion(mid),isBadVersion(mid+1)的情况,避免重复调用
            q=isBadVersion(mid);
            r=isBadVersion(mid+1);
            if(p!=r)
            {
                if(q) return mid;
                else if(!q) return mid+1;
            }
            else{
                if(!q) left=mid+1;
                else right=mid-1;
            }
        }
        return (right+left)/2;
    }
};
后来看过官方题解后发现,只需要不断的区间范围,即确定第一个错误版本的在那一边既可以不断的缩小区间直到将区间缩小到只剩一个元素,此时该元素即为第一个错误版本。
class Solution {
public:
    int firstBadVersion(int n) {
        int left = 1, right = n;
        while (left < right) { // 循环直至区间左右端点相同
            int mid = left + (right - left) / 2; // 防止计算时溢出
            if (isBadVersion(mid)) {
                right = mid; // 答案在区间 [left, mid] 中
            } else {
                left = mid + 1; // 答案在区间 [mid+1, right] 中
            }
        }
        // 此时有 left == right,区间缩为一个点,即为答案
        return left;
    }
};
作者:LeetCode-Solution
链接:https://leetcode.cn/problems/first-bad-version/solution/di-yi-ge-cuo-wu-de-ban-ben-by-leetcode-s-pf8h/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

例三

搜索插入位置
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
请必须使用时间复杂度为 O(log n) 的算法。

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/search-insert-position
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

主要思路和例二相同,类似二分插入的思路,即不断的缩小区间范围,若区间长度等于1或区间长度为0(left>right),即返回区间的最左处的值,此时可以确定位置

class Solution {
public:
    int searchInsert(vector<int>& nums, int target) {
        int left=0;
        int right=nums.size()-1;
        while(left<=right)
        {
            int mid=left+(right-left)/2;
            if(nums[mid]<target) left=mid+1;
            else right=mid-1;//只要不相等,就让right=mid-1,这样当left=right时匹配成功,left的值就是此时mid的值,若匹配失败,则left的值就该为应该插入的位置
       }
       return left;
    }
};

标签:right,--,mid,int,版本,区间,刷题,leetcode,left
From: https://www.cnblogs.com/zz-gy/p/17041403.html

相关文章

  • 每日食词—day093
    splitv. n. adj.分裂、分割、切分、分隔、拆分assignmentn.赋值、分配、指派、指定convertv. n.转换、转化、转变、改变preservev. n.保护、保存、保持......
  • unityShader入门精要 渲染流水线
    应用阶段把数据加载到显存中设置渲染状态调用DrawCall几何阶段顶点着色器顶点着色器需要完成的工作主要有:坐标变换和逐顶点光照坐标变换:就是对顶点的......
  • FastAPI学习
      fromfastapiimportFastAPIfromenumimportEnumfrompydanticimportBaseModelfromtypingimportUnionapp=FastAPI()classModelName(str,Enum):......
  • Java(SpringBoot)项目打包(构建)成`Docker`镜像的几种方式
    前置说明最为原始的打包方式spring-boot-maven-plugin插件jib-maven-plugin插件dockerfle-maven-plugin插件最为原始的方式也就是使用Docker的打包命令去打包,麻......
  • vulnhub靶场之BUFFEMR: 1.0.1
    准备:攻击机:虚拟机kali、本机win10。靶机:BUFFEMR:1.0.1,下载地址:https://download.vulnhub.com/buffemr/BuffEMR-v1.0.1.ova,下载后直接vbox打开即可。知识点:openemr框架......
  • 数据结构 玩转数据结构 8-5 Heapify 和 Replace
    0课程地址https://coding.imooc.com/lesson/207.html#mid=13742 1重点关注1.1最大二叉堆替换元素replace见3.1 1.2普通数组转最......
  • Django入门
    入门首先是注意这个发音:D是不发音的,jangoDjango是使用Python语言编写的一个广受欢迎且功能完整的服务器端网站框架。可以方便创建一个基本可用,安全,可扩展,可维护的项......
  • BBS项目修改密码及退出登录思路总结
    BBS项目修改密码及退出登录思路总结创建超级管理员用户和登录步骤一、修改密码编写步骤概览开设修改密码路由首页前端代码写Ajax请求回到后端继续修改密码逻辑......
  • 01.09-01.15文献阅读总结
    ......
  • ubuntu22.04 myslq初始化配置
    1.装包sudoaptinstallmysql-server-y2.初始化ubuntu22.04默认安装mysql8新建mysql是没有密码的mysql-uroot-p ALTERUSER'root'@'localhost'IDENTI......