数据结构:二分查找模版与例题

欢迎关注我的简书:https://www.jianshu.com/u/55a1bc4688c6
本文源自LeetCode二分查找章节,通过本章节的练习对二分查找的基础知识进行掌握,同时能够利用二分查找解决部分问题。二分查找是一个效率非常高的算法,它充分利用了元素间的次序关系,采用分治策略,可在最坏的情况下用O(log n)完成搜索任务。掌握二分查找对于提升代码效率很有帮助。
LeetCode二分查找地址:https://leetcode-cn.com/explore/learn/card/binary-search/208/background/832/
本篇文章将介绍3个二分模版,同时完成十个例题。在阅读过程中,如果对三个模板的区别难以理解,请务必完全阅读完,这是一个需要逐步思考的过程。
给个目录:
LeetCode704 二分查找
LeetCode69 x 的平方根
LeetCode374 猜数字大小
LeetCode33 搜索旋转排序数组
LeetCode278 第一个错误的版本
LeetCode75 寻找峰值
LeetCode159 寻找旋转排序数组中的最小值
LeetCode34 在排序数组中查找元素的第一个和最后一个位置
LeetCode658 找到 K 个最接近的元素

二分查找基础知识

什么是二分查找
二分查找是计算机科学中最基本、最有用的算法之一。 它描述了在有序集合中搜索特定值的过程。

二分查找中使用的术语:

目标 Target —— 你要查找的值
索引 Index —— 你要查找的当前位置
左、右指示符 Left,Right —— 我们用来维持查找空间的指标
中间指示符 Mid —— 我们用来应用条件来确定我们应该向左查找还是向右查找的索引

二分查找原理

二分查找是一种在每次比较之后将查找空间一分为二的算法。每次需要查找集合中的索引或元素时,都应该考虑二分查找。如果集合是无序的,我们可以总是在应用二分查找之前先对其进行排序。

二分查找一般由三个主要部分组成:

预处理 —— 如果集合未排序,则进行排序。
二分查找 —— 使用循环或递归在每次比较后将查找空间划分为两半。
后处理 —— 在剩余空间中确定可行的候选者。

二分查找是一个效率非常高的算法,它充分利用了元素间的次序关系,采用分治策略,可在最坏的情况下用O(log n)完成搜索任务。掌握二分查找对于提升代码效率很有帮助。

复杂度
二分查找的时间复杂度:O(log n),因为二分查找是通过对查找空间中间的值应用一个条件来操作的,并因此将查找空间折半,在更糟糕的情况下,我们将不得不进行 O(log n) 次比较,其中 n 是集合中元素的数目。
二分查找的空间复杂度:O(1),不需要任何其他额外空间。

LeetCode704 二分查找

我们先来一道最为基础的二分查找题目,理解一下二分查找。
本题为LeetCode704 二分查找,属于二分查找中最为基础的练习。二分查找,顾名思义,就是将数组一分为二,在左右两边查找,确定元素区间之后再次一分为二,直至确定元素。

题目

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

示例 1:

输入: nums = [-1,0,3,5,9,12], target = 9
输出: 4
解释: 9 出现在 nums 中并且下标为 4

示例 2:

输入: nums = [-1,0,3,5,9,12], target = 2
输出: -1
解释: 2 不存在 nums 中因此返回 -1

提示:

你可以假设 nums 中的所有元素是不重复的。
n 将在 [1, 10000]之间。
nums 的每个元素都将在 [-9999, 9999]之间。

C++代码

class Solution {
   
public:
    int search(vector<int>& nums, int target) {
   
        int left = 0;
        int right = nums.size()-1;
        while(left<=right){
   
            int mid = (left+right)/2;  //计算计算中间值
            if(nums[mid]==target) return mid; //如果找到了target,返回当前的索引
            if(nums[mid]<target) left = mid+1; //如果nums[mid]<target,证明正确的值在当前位置的右边
            if(nums[mid]>target) right = mid-1; //如果nums[mid]>target,证明正确的值在当前位置的左边
        }
        return -1;
    }
};

体会

本题是二分查找最为基础的题目,对于理解二分查找非常重要。

二分查找 模版#1

模板 #1 是二分查找的最基础和最基本的形式。这是一个标准的二分查找模板,是非常基础简单的二分查找。模板 #1 用于查找可以通过访问数组中的单个索引来确定的元素或条件。模版#1 不需要后处理,因为每一步中,你都在检查是否找到了元素。如果到达末尾,则知道未找到该元素。

模版#1 对应的例题为:
LeetCode69 x 的平方根
LeetCode374 猜数字大小
LeetCode33 搜索旋转排序数组

模版#1 C++代码

int binarySearch( vector<int> & nums, int target )
{
   
	if ( nums.size() == 0 )
		return(-1);
	int left = 0, right = nums.size() - 1;
	while ( left <= right )
	{
   
		/* Prevent (left + right) overflow */
		int mid = left + (right - left) / 2;
		if (nums[mid] == target) return mid;
		else if ( nums[mid] < target ) left = mid + 1;
		else right = mid - 1;
	}
	/* End Condition: left > right */
	return(-1);
}

语法关键

初始条件:left = 0, right = length-1
终止:left > right
向左查找:right = mid-1
向右查找:left = mid+1

LeetCode69 x 的平方根

题目

实现 int sqrt(int x) 函数。

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

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

示例 1:

输入: 4
输出: 2

示例 2:

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

C++代码

class Solution {
   
public:
    int mySqrt(int x){
   
        int left = 0;
        int right = x;
        if (x <= 1) return x;
        int ans= 0;
        while(left<=right){
   
            int mid = (right+left) /2; //计算中间值
            if(x/mid >= mid ) {
   
                left = mid+1
  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值