二分查找的思想

C++算法——二分法查找 本章介绍了二分查找的算法思想,并且整理了相关的经典题目,从简单到难的去逐步递进,并且提供了链接和描述,可以直接通过链接去练习,或者直接看本篇博客去尝试思考解题,还提供了参考的思路,部分困难的题目会结合图像去分析,还有测试通过的参考代码 阅读详情

先看看leetcode两道相关的题目,都是二分思想的应用。
leetcode 35 https://leetcode-cn.com/problems/search-insert-position/
leetcode 34 https://leetcode-cn.com/problems/find-first-and-last-position-of-element-in-sorted-array/

二分思想用一句话概况就是“一看就懂,一写就废”,花了很长时间都没有弄得懂,每个人都是不同的写法,新手很难从中发现规律。
其实二分查找最重要的一句话就是“查找范围”,如何确定查找范围?只要确定了查找范围,二分查找其实都是一个套路。而二分查找大致分为以下三种:

①普通二分,也就是给定一个排序数组nums和目标值target,在nums中查找target,如果找到就返回下标。写法也非常简单:

int left = 0;
int right = nums.size() - 1;
while(left <= right){    //查找范围[left, right]
	int mid = left + (right - left) / 2;
	if(nums[mid] < target){
		left = mid + 1;  //查找范围缩小为[mid+1, right]
	} else if(nums[mid] > target){
		right = mid - 1; //查找范围缩小为[left, mid-1];
	} else if(nums[mid] == target){
		return mid;
	}
}
return -1;

初学建议不要写else,一步一步else if分析会更容易理解其中的“查找范围”如何思考。
下面两种是二分查找的变种,比基本二分要难一点。由于需要确定边界,所以不能一找到nums[mid] == target就返回,而应该继续缩小查找范围,不断逼近边界。

②确定左侧边界的二分查找
需求:给定一个排序数组nums和一个目标值target,在nums中找到target出现的最左侧位置,返回该下标。先给出代码再作解释:

int left_bound(vector<int> nums, int target){
	if(nums.size() <= 0){
		return -1;
	}
	int left = 0;
	int right = nums.size();
	while(left < right){     //查找范围为[left, right)
		int mid = left + (right - left) / 2;
		if(nums[mid] > target){
			right = mid;     //查找范围缩小为[left, mid)
		} else if(nums[mid] < target){
			left = mid + 1;  //查找范围缩小为[mid + 1, right)
		} else if(nums[mid] == target){
			right = mid;     //注意这里!right往左靠, 查找范围为[left, mid)
		}
	}
	if(left == nums.size() || nums[left] != target){
		return -1;           //target比nums所有数都大,那么就找不到了
	}
	return left;             //否则此时left就是左边界
}

注意到上面的代码,首先确定查找范围!这篇文章我全部采用左闭右开区间的查找范围,当然也可以左闭右闭。
而right一开始为什么是nums.size()而不是nums.size() - 1呢?这是因为查找范围为[left, right)左闭右开,为了确保所有的数都能被用到,所以right = nums.size(); 这样就可以取到nums[nums.size() - 1],也即最后一个数了。
好了,上面说完查找范围的确定,那确定左边界就是不断往左逼近了。简单地说,就是区间尽量往左靠,不断往左边缩小区间,具体的体现就是当 nums[mid] == target的时候,并不是直接返回,而是把right = mid; 把查找区间往左边缩小为[left, mid),因为mid已经被我们用过了(也就是已经和target比较过了),而右区间又是开区间,所以right = mid而非mid - 1!
那为什么left = mid + 1呢?这是因为我们左区间是闭区间,当mid被用过之后,下一个区间就是mid + 1开始了。
到了这里,相信大家对思路已经明白了,最后就是循环退出的时候,进行异常情况的判断,循环退出的时候,left == right。
此时,有两种情况:1. 找到了左边界。 2.找不到左边界。
找不到左边界是什么情况呢?要么left = nums.size()超出数组下标(target比所有nums的数都大),要么nums[left] != target,至此结束。

③确定右侧边界的二分查找
需求:给定一个排序数组nums和一个目标值target,在nums中找到target出现的最右侧位置,返回该下标。
还是先给出代码:

int right_bound(vector<int> nums, int target){
	if(nums.size() <= 0){
		return -1;
	}
	int left = 0;
	int right = nums.size();
	while(left < right){     //查找范围为[left, right)
		int mid = left + (right - left) / 2;
		if(nums[mid] > target){
			right = mid;     //查找范围缩小为[left, mid)
		} else if(nums[mid] < target){
			left = mid + 1;  //查找范围缩小为[mid + 1, right)
		} else if(nums[mid] == target){
			left = mid + 1;     //注意这里!left往右靠, 查找范围为[mid + 1, right)
		}
	}
	return right - 1;         //注意这里的返回值
}

分析思路同上:既然要找最右边界,那么left就要不断往右靠,查找范围同样是[left, right),相信大家已经可以自己分析出来了。
那么最终的返回值是什么呢?我们知道,循环退出的时候left ==rigiht,由于有可能出现在最后一个数,所以我们返回right - 1(left - 1也可以)。这里是一个小细节,因为上面找到target并缩小区间时,是这样写的

else if(nums[mid] == target){
		left = mid + 1;     //注意这里!left往右靠, 查找范围为[mid + 1, right)
}

所以真正的mid = left - 1(mid就是我们找到的目标值下标),这也是上面返回left的原因。

到此,大家可以去试一试上面两道题,采用这思路解决,会在O(logn)复杂度解决。下面是我写的代码:

34. 在排序数组中查找元素的第一个和最后一个位置

class Solution {
public:
    vector<int> searchRange(vector<int>& nums, int target) {
        if(nums.size() <= 0){
            return vector<int>{-1, -1};
        }
        vector<int> res(2, -1);
        int left = 0;
        int right = nums.size();
        while(left < right){        //搜索区间[left, right)
            //寻找左边界, right左靠
            int mid = left + (right - left) / 2;
            if(nums[mid] > target){
                right = mid;
            } else if(nums[mid] < target){
                left = mid + 1;     //mid已经被搜索过了, 下一个[mid + 1, right)
            } else if(nums[mid] == target){
                right = mid;        //right左靠
            }
        }
        //异常情况判断: 比数组所有数都大 / 不存在target
        if(left == nums.size() || nums[left] != target){
            return res; 
        }
        res[0] = left;              //确定左边界

        left = 0;
        right = nums.size();
        while(left < right){        //搜索区间[left, right)
            //寻找右边界, left左靠
            int mid = left + (right - left) / 2;
            if(nums[mid] > target){
                right = mid;        //mid已经被搜索过了, 右开区间, 所以 [left, mid)
            } else if(nums[mid] < target){
                left = mid + 1;     //mid已经被搜索过了, 下一个[mid + 1, right)
            } else{
                left = mid + 1;     //left右靠
            }
        }
        if(nums[left - 1] != target){
            return res;
        }
        res[1] = left - 1;          //注意, 因为搜索到mid的时候, left = mid + 1
        return res;
    }
};

35. 搜索插入位置

class Solution {
public:
    int searchInsert(vector<int>& nums, int target) 
    {
        if(nums.size() <= 0){
            return 0;
        }
        int left = 0;
        int right = nums.size();
        while(left < right){  //搜索区间[left, right)
            int mid = left + (right - left) / 2;
            if(nums[mid] < target){
                left = mid + 1;
            } else if(nums[mid] > target){
                right = mid;
            } else{
                return mid;
            }
        }
        return left;
    }
};
递归-PTA二分查找 输入n值(1<=n<=1000)、n个非降序排列的整数以及要查找的数x,使用二分查找算法查找x,输出x所在的下标(0~n-1)及比较次数。若x不存在,输出-1和比较次数。 输入格式: 输入共三行: 第一行是n值; 第二行是n个整数; 第三行是x值。 输出格式: 输出x所在的下标(0~n-1)及比较次数。若x不存在,输出-1和比较次数。 输入样例: 4 1 2 3 4 1 输出样例: 0 2 #include<stdio.h> int main(){ int n,x; int a[10 阅读详情

相关推荐

减治思想——二分查找详细总结

🚀 优质资源分享 🚀 学习路线指引(点击解锁) 知识定位 人群定位 🧡 Python实战微信订餐小程序 🧡 进阶级 本课程是python flask+微信小程序的完美结合,从项目搭建到腾讯云部署上线,打造一个全栈订餐系统。 💛Python量化交易实战💛 入门级 手把手带你打造一个易扩展、更安全、效率更高的量化交易系统 减治思想——二分查找详细总结 二分查找应用于有序数组,可以在以O(log(n))O(log⁡(n))O(\log(n))时间复杂度进行查找。其思想在于利用数组的有序性直

「 虚幻私塾」 1163

[数据结构]深入理解二分查找

1.二分查找的基本思想 二分查找的基本思想是将n个元素分成大致相等的两部分,取a[n/2]与x做比较 a. 如果x=a[n/2],则找到x,算法中止 b. 如果x<a[n/2],则只需要在数组a的左半部分继续搜索x c.如果x>a[n/2],则只需要在数组a的右半部分继续搜索x 2.二分查找时间复杂度 时间复杂度即是while循环的次数 总共有n个元素,渐渐跟下去就是n,n/2,n/4,... ,n/2^k 由于2^k取整后为>=1 即令n/2^k=1 可得k=log2

wodengniyujiul的博客 2308

二分查找的思想及实现

1.二分查找: 又称为 折半查找,二分查找,适合对已经排序好的数据集合进行查找,时间复杂度O(log2n),效率高。假设有一升序的数据集合,先找出升序集合中最中间的元素,将数据集合划分为两个子集,将最中间的元素和关键字key进行比较,,如果等于key则返回,如果大于关键字key,则在前一个数据集合中查找,否则在后一个子集中查找,直到找到为止,如果没找到则返回-1; 2.算法步骤描述: (1)首先确定整个查找区间的中间位置mid=(low+high)/2; (2)用待查关键字值与中间位置关键字值进行比较; 若

xingbingle的博客 1871

二分查找的基本思想及实现

要求在有序数组中进行二分查找,不是有序,则要先排序 思路: 1.首先确定该数组的中间的下标 mid=(left+right)/2; 2.然后让需要查找的数findvalue和arr[mid]比较 3.findvalue>arr[mid],说明该数在mid的右边,因此需要递归向右查找 4.findvalue<arr[mid],说明你要查找的数在mid的左边,因此需要递归向左查找 5.findvalue=arr[mid],找到返回 6.当left大于right,说明没找到,返回-1; 在返回的时候

JSUITDLWXL的博客 851

NY8A053E 例程 之 PWM Ouput

更多关于NY8A053E的相关例程请留言!

倪彬笑阳的博客 2924

3D美术14——max——fbx导入max后直接生成bip人形骨骼插件

最近经常会从unity里反八FBX到max里进行2次修改。 但是非常尴尬的事情就是,就是用max做的fbx,你在反导入回来,BIP骨骼都会变成预制体。这个时候有一个方法补救。那就是在导入的时候调整一下参数。(如下图) 把这里调整成设置为骨骼。就还可以了。 但是,如果你不是用max做的FBX。呵呵,那么你一定很头大,因为完全没有用。 所以,这个时候就要上插件了。 Autofbxtobip v.1.1 这个插件适用于2015及其以上版本。 在这之前我还用过一款叫BIPPY,但是效果相当感人,照着这个图片调整

qq_37576129的博客 1万+

java二分查找的思想_java中二分查找的思想是什么?算法实例展示

在我们学习java的过程中有时会遇到一些问题,它们对于我们的学习来说是一个锻炼的机会。今天就来为大家介绍java中二分查找的思想是什么以及它的算法实例展示。一起来看看吧。一、 基本思想二分查找的基本思想是,假设R[low..high]是当前的查找区间1.首先确定该区间的中点位置:mid=[﹝low+high﹞/2]2.然后将待查的K值与R[mid].key比较。如果相等,那么查找成功并返回此位置,...

weixin_39875675的博客 309

深度学习模型轻量化方法之【量化】

量化虽然有着硬件友好和功效提升的特点,但它也引入了模型性能的折衷。因此,设计有效的量化策略需要在模型大小、性能以及运算速度之间做出平衡。随着深度学习算法和硬件加速技术的快速发展,量化方法在使深度网络轻量化和提高部署效率方面持续发挥着重要作用。

m0_73916791的博客 2846

【算法思想04】二分查找

从基本思想与实现、性能分析、应用三方面学习二分查找算法,并整理了部分可使用二分查找解决的例题。

甜鲸鱼的博客 924

【从零开始学Skynet】实战篇《球球大作战》(一):功能设计

为了能把之前在基础篇中学习到的Skynet的各种知识结合起来,所以在实战篇中,我们准备开发一个完整的游戏案例《球球大作战》,介绍分布式游戏服务端的实现方法。

我是一条寻水的鱼 2978

【数据结构】考点二十八 : 二叉树的概念:二叉树的度、完全二叉树、满二叉数结点数、哈夫曼结点数、完全二叉树的深度

二叉树(Binary Tree)是一种常见的数据结构,它或者为空(null),或者由一个根节点(root node)和两个子树(left subtree 和 right subtree)组成,这两个子树又分别是一棵二叉树。二叉树的每个节点最多有两个子节点,通常称为左子节点(left child)和右子节点(right child)。

超越的博客 1737

深度理解二分查找思想~

二分思想是将有序数组分成两半,通过比较数组中间元素与目标值大小,来决定下一步搜索的区间是左半部分还是右半部分,然后递归再选定的区间内继续查找。(部分有序的数组也可使用这一思想)

卷心菜是俺的博客 1326

inno setup自定义卸载程序和美化

也就是DisplayName,因为我们在第一步的时候,将卸载程序名称也写入了注册表,所以,我们直接从注册表读DisplayName字段即可。1.要实现inno setup自定义卸载程序,首先需要关闭自带的卸载程序。在[Setup]的字段关闭卸载程序步骤和页面。2.删除应用程序目录里能够删除的并且返回进度。3.自定义卸载程序相关的注册表信息。4.删除启动菜单栏和guid注册表。2.自定义快捷方式和程序菜单。

cs821984831的博客 2347

二分查找思想

二分查找   二分查找思想应用于对有序的数组进行查找操作。 时间复杂度   二分查找也称为折半查找,每次都能将查找区间减半,这种折半特性算法时间复杂度为O(logn)。 mid计算 有两种计算中值mid的方式: m=(l+h)/2 m=l+(h-l)/2   l+h可能出现加法溢出,也就是说加法的结果大于整形能够表示的范围。但是l和h都为正数,因此h-l不会出现加法溢出的问题。所以,最好使用第...

weixin_30484739的博客 646

Claude Code 100个真实案例 - 用AI设计Arduino PCB电路板(硬件小白也能画板)

本案例展示如何使用 Claude Code 配合 KiCad 的 Python 脚本接口,从零设计一块 Arduino 传感器扩展板 PCB。从原理图符号创建、网表生成到 PCB 布局布线,全程自动化完成,最终输出可直接发给工厂打样的 Gerber 文件。

yueyeguzhuo的专栏 437

逻辑回归:利用Python实现二分类算法

通过使用Python编写的代码,我们可以训练逻辑回归模型并进行预测。接下来,我们将实现逻辑回归算法的训练函数。训练函数将接受训练数据集X和对应的标签y,以及学习率alpha和迭代次数num_iterations。训练完成后,我们可以使用训练得到的参数theta来进行预测。在这个例子中,我们有一个包含4个样本的训练数据集X,每个样本有两个特征。在这个例子中,如果预测概率大于等于0.5,则预测为类别1,否则预测为类别0。现在,我们可以使用训练函数来训练模型。根据给定的样本x_new,预测函数将返回相应的类别。

XlltEditor的博客 326

二分查找的基本思想及其代码实现

文章目录前言一、二分查找基本概念1、前提条件2、基本思想二、代码实现(Java)2.读入数据总结学习内容:学习时间:学习产出: 前言 本文介绍了二分查找法的使用方法及其思想原理,相应的代码使用的是Java语言 一、二分查找基本概念 1、前提条件 二分查找也叫折半查找,它的前提条件是被搜索的序列是有序的(升序或降序),且元素是不重复的。 例如:{2,5,8,10,56,94},我们要查找当中的某一个数,就可以使用二分查找法 而{1,3,2,6,9,4},{1,1,5,3,6,6,9}这样的序列就不可以使用二

han_tiao_tiao的博客 2800

IMSL CNL 7.0.0 (x86-64)Crack

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

【算法与数据结构】二分查找思想

二分查找(binary search)是一种基于分治策略的高效搜索算法。它利用数据的有序性,每轮缩小一半搜索范围,直至找到目标元素或搜索区间为空为止,其实有时候数据没有序也能用二分查找思想解题,遇到具体的题我们具体分析。

春风不语。 1449

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

【优选算法】(实战感悟二分查找算法的思想原理)

二分查找算法解析 本文详细介绍了二分查找算法的核心原理与应用场景。二分查找是一种针对有序数据集的高效查找算法,通过不断将查找范围缩小一半,将时间复杂度从线性查找的O(n)优化至O(log n)。文章首先阐述了二分查找的适用前提:数据必须有序、支持随机访问且为静态数据。然后通过图解和代码示例,展示了二分查找的标准实现流程,包括边界条件处理、中间值计算和三种情况的处理逻辑。文章还提供了完整的测试代码,通过多个测试用例验证算法的正确性。最后强调二分查找的核心价值在于其"分而治之"的思想。

承于所学,探技术之渊;以代码求政,寻成长之道。 1万+

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

二分查找与分治思想的关联?

它的基本思想是将待查找区间划分为两个子区间,然后比较子区间中元素的差异来确定目标元素的位置。在未来,随着计算机技术的不断发展,我们期待看到更多关于二分查找和分治思想的优秀文章和研究成果。2. 提高算法稳定性:在二分查找过程中,我们通过比较不同子区间中元素的差异来确定最优解的位置。1. 优化搜索空间:通过将问题分解为更小的、更易于处理的部分,分治思想可以有效地降低搜索空间的大小。分治思想是一种重要的算法思想,它通过将问题分解为更小的、更易于处理的部分,从而达到解决复杂问题的目的。

searchboy2025的博客 74

简单二分查找和递归的思想

递归是一种重要的编程思想,在学习数据结构时,经常用到递归的思想。就是让函数在一定条件下不断的调用自己,从而求解。思考起来逻辑更为简单,代码更加简洁,但是也容易出现死循环,并且代码的扩展性和可读性不好。今天我写了二分查找的递归算法和非递归算法。      二分查找是用来从一个有序数组中查找某一个值是否存在,我们拿需要查找的值和数组的中间值不断的比较,以升序数组为例,如果查找的值大于数组中间的值,则

spring_wu 1006

二分查找算法基本思想

  转载http://www.cppblog.com/converse/archive/2009/10/05/97905.html 二分查找算法基本思想二分查找算法的前置条件是,一个已经排序好的序列(在本篇文章中为了说明问题的方便,假设这个序列是升序排列的),这样在查找所要查找的元素时,首先与序列中间的元素进行比较,如果大于这个元素,就在当前序列的后半部分继续查找,如果小于这个元素,就...

weixin_34174422的博客 1842

二分查找法思想

二分查找法思想  (2012-07-29 21:00:54) 转载▼ 标签:  二分查找   it 分类: 数据结构-C语言     算法:当数据量很大适宜采用该方法。采用二分法查找时,数据需是排好序的。   基本思想:假设数据是按升序排序的,对于给定值x,从序列的中间位置开始比较,如果当前位置值等于x,则查找成

gaoqiao1988的专栏 1516

二分查找思想及其代码实现

二分查找法学习

qq_31830173的博客 185

【小白系列】 简单的二分查找思想

超级小白的简单二分法思想及运用。

GMfengyi的博客 489
上一篇: 基于C++写一个线程池
下一篇: shared_ptr源码结构分析
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值