LeetCode 20天算法刷题计划第一天:二分查找

目录

  • 前言
  • 1.704二分查找
    • 1.1题目链接
    • 1.2题目描述
    • 1.3题目分析
    • 1.4代码实现
  • 2.278.第一个错误版本
    • 2.1题目链接
    • 2.2题目描述
    • 2.3题目分析
    • 2.4代码实现
  • 3.35搜索插入位置
    • 3.1题目链接
    • 3.2题目描述
    • 3.3题目分析
    • 3.4代码实现
  • 后记

前言

hello,大家好,博主开了一个题海求知的专栏,用来记录一些刷题过程中的收获,感谢大家的支持。今天我们开始第一篇文章,有关于二分查找。
在博主写这篇的同时,手机里正在放着英仙座流星雨的直播,很期待一场盛大的流星雨。
LeetCode 20天算法刷题计划第一天:二分查找_第1张图片
好的,让我们正式开始我们的博文吧。

1.704二分查找

1.1题目链接

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

1.2题目描述

给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。

LeetCode 20天算法刷题计划第一天:二分查找_第2张图片

1.3题目分析

如果我们追根溯源一下,二分查找的思想在我们中小学阶段就已经接触过了。记不记得高中有一种题目是求对数的值的区间,通常作为选择题的前三道出现。我们确定那个区间用到的方法就是二分法。再向前追溯,在小学阶段,有一种很经典的题是用一个天平最快找出10个球中质量不合格的球,我们要每次平均分然后称重。其实这些都是二分的思想。
那么什么是二分法呢?我们来看一下:
LeetCode 20天算法刷题计划第一天:二分查找_第3张图片

(1)首先,从数组的中间元素开始搜索,如果该元素正好是目标元素,则搜索过程结束,否则执行下一步。
(2)如果目标元素大于/小于中间元素,则在数组大于/小于中间元素的那一半区域查找,然后重复步骤(1)的操作。
(3)如果某一步数组为空,则表示找不到目标元素。
二分法查找的时间复杂度O(logn)。

1.4代码实现

我们这里用的是C语言

int search(int* nums, int numsSize, int target)
{
   int left=0;
   int right=numsSize-1;
   int mid;
   while(left<=right)
   {
       mid=left+(right-left)/2;
       if(target>nums[mid])
       {
           left=mid+1;
       }
       if(target<nums[mid])
       {
           right=mid-1;
       }
       if(target==nums[mid])
       {
           return mid;
       }
   }
   return -1;
}

观察上述代码,我们需要注意一个问题
LeetCode 20天算法刷题计划第一天:二分查找_第4张图片
这里我们为什么要这样写呢?我们直接写出mid=(left+right)/2.不可以吗?
答案是如果我们这样写也可以编译通过,但这不是一种良好的写法。请试想一下,如果我们的数组非常大,right的值就会很大,很有可能超过int可以表示的范围哦。但如果我们换一种写法:

LeetCode 20天算法刷题计划第一天:二分查找_第5张图片
所以,我们建议最好采取mid=left+(right-left)/2;这种写法。
还有我们要注意的是+1,-1
LeetCode 20天算法刷题计划第一天:二分查找_第6张图片
博主在第一次提交的时候没有写,编译没有通过。我们想,既然需要重新改变左值或者右值了,肯定不是mid值了,于是+1,-1可以提高代码效率。

2.278.第一个错误版本

2.1题目链接

https://leetcode-cn.com/problems/first-bad-version/

2.2题目描述

你是产品经理,目前正在带领一个团队开发新的产品。不幸的是,你的产品的最新版本没有通过质量检测。由于每个版本都是基于之前的版本开发的,所以错误的版本之后的所有版本都是错的。
假设你有 n 个版本 [1, 2, …, n],你想找出导致之后所有版本出错的第一个错误的版本。
你可以通过调用 bool isBadVersion(version) 接口来判断版本号 version 是否在单元测试中出错。实现一个函数来查找第一个错误的版本。你应该尽量减少对调用 API 的次数。

LeetCode 20天算法刷题计划第一天:二分查找_第7张图片

2.3题目分析

我们先理解一下这个题目,在某一个版本后,所以版本都是错误的了,也就是说存在一个版本,在它之前都是正确的,在它之后都是错误的。
LeetCode 20天算法刷题计划第一天:二分查找_第8张图片
这依旧可以通过二分查找的思想来解决。设定左右边界之后,每次我们都依据左右边界找到其中间的版本,检查其是否为正确版本。如果该版本为正确版本,那么第一个错误的版本必然位于该版本的右侧,我们缩紧左边界;否则第一个错误的版本必然位于该版本及该版本的左侧,我们缩紧右边界。
这样我们每判断一次都可以缩紧一次边界,而每次缩紧时两边界距离将变为原来的一半,因此我们至多只需要缩紧 O(logn) 次。

2.4代码实现

C语言

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;
}

3.35搜索插入位置

3.1题目链接

https://leetcode-cn.com/problems/search-insert-position/

3.2题目描述

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

LeetCode 20天算法刷题计划第一天:二分查找_第9张图片

3.3题目分析

这其实也是二分法的运用。注意,题目要求是返回插入的位置,这也就是说,如果数字在数组中存在,我们就通过二分查找找到他的位置,如果不存在,我们也可以知道比它大和比它小的值,那么当它插入进去的时候比它大的第一个数的位置就是他插入后他的位置。

3.4代码实现

C语言

int searchInsert(int* nums, int numsSize, int target) 
{
	int left = 0, right = numsSize;

	while (left < right)
	{
		int mid = left + (right - left) / 2;

		if (nums[mid] >= target)
		{
			right = mid;
		}
		else
		{
			left = mid + 1;
		}
	}

	return left;
}

后记

好的,我们今天题海求知的博文就分享到这里啦。现在是2021年8月13日的凌晨两点,在写这篇博文的过程中我也在看英仙座流星雨的直播,目前还没有看到大片的流星雨,但是还是从直播中看到了一些分散的流星雨。
LeetCode 20天算法刷题计划第一天:二分查找_第10张图片
最开始我是在B站上看人民日报的直播,可是不久前却卡了。
LeetCode 20天算法刷题计划第一天:二分查找_第11张图片
LeetCode 20天算法刷题计划第一天:二分查找_第12张图片

于是转战央视新闻的直播啦。
LeetCode 20天算法刷题计划第一天:二分查找_第13张图片
老夜猫子的我现在还不打算睡,希望今晚可以如愿看到大片的流星雨,也觉得此时此刻还有很多人正在一起期盼这片星空是一件很美好的事情。大家看到这篇文章也在心里默默许一个愿望吧,也许会实现哦。祝我们都有好运,这篇博文先到这里,拜拜啦。

你可能感兴趣的:(题海求知,算法,二分法)