JavaScript中的二分查找法怎么使用

免费教程   2024年05月10日 5:02  

这篇文章主要介绍“JavaScript中的二分查找法怎么使用”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“JavaScript中的二分查找法怎么使用”文章能帮助大家解决问题。

二分查找公式functionbinarySearch(nums,target){letleft=0letright=...while(...){constmid=Math.floor(left+(right-left)/2)if(nums[mid]===target){...}elseif(nums[mid]<target){left=...}elseif(nums[mid]>target){right=...}}return...}

分析二分查找技巧 不要出现else,而是把所有情况用else if 写清楚,这样可以清楚的展示所有细节。

Math.floor(left + (right - left) / 2)其实和Math.floor((left +right)/2)的结果是一样的。如果left和right很大的时候,相加会导致移除。Math.floor(left + (right - left) / 2)可以有效的防止溢出。

寻找一个数varsearch=function(nums,target){letleft=0;letright=nums.length-1;while(left<=right){constmid=Math.floor(left+(right-left)/2);if(nums[mid]===target){returnmid;}elseif(nums[mid]>target){right=mid-1;}elseif(nums[mid]<target){left=mid+1;}}return-1;};

力扣第704题二分查找 这题是二分查找最简单的题型,几乎所有的二分查找的题型都是根据这个拓展的。

我们首先考虑的是搜索区间。因为定义的right为nums.length - 1,所以搜索区间为[left, right]两端都闭。当查找到了目标元素,则停止搜索退出循环,然后返回目标值对应的索引。

当没有找到目标元素,循环的终止条件为left === right + 1的时候,直接返回-1即可。

缺陷

如果给你个有序数组nums = [1,2,2,2,3],target为2,此时用上面的方法返回的索引是2。如果我们想得到的target的在nums中最左边满足条件的值,或者最右边满足条件的值,这种方法就有问题了。

可能会想到,当找到了target的值,然后向左,向右做线性搜索。但是这样就很难保证二分查找对数级的复杂度了。

寻找最左边满足条件的值方式一functionleftBound(nums,target){letleft=0;letright=nums.length;while(left<right){constmid=Math.floor(left+(right-left)/2);if(nums[mid]===target){right=mid;}elseif(nums[mid]<target){left=mid+1;}elseif(nums[mid]>target){right=mid;}}if(left===num.length)return-1;returnnums[left]===target?left:-1;}

上面是一种比较常见的代码形式。但是和我们刚开始的框架是可以匹配的。在这里while中使用的<,而不是<=。因为我们在定义right的时候,是nums.length而不是nums.length-1。那就说明我们的搜索区间是在[left,right)左闭右开。所以终止条件就是当left == right的时候。

还会发现一个不一样的地方,right = mid而不是right = mid - 1,这个还是受上面的搜索区间的影响。因为搜索区间为[left,right)左闭右开,所以当nums[mid]被检测到的时候,下一步应该缩小搜索区间。当nums[mid] === target的时候,虽然已经找到了target的值,但是不要立即返回,而是缩小搜索区间为[left, mid)。然后不断的向左边收缩,直到锁定左侧边界,也就是当left == right的时候。

最后,考虑下越界情况,当left的值为nums.length的时候说明查找左侧边界已经超出了搜索区间,说明target的值比所有数都大。当left的值为target的时候,说明找到了直接返回即可。然后其实返回left和返回right都一样,因为我们的终止条件是left == right。

方式二functionleftBound(nums,target){letleft=0;letright=nums.length-1;while(left<=right){constmid=Math.floor(left+(right-left)/2);if(nums[mid]<target){left=mid+1;}elseif(nums[mid]>target){right=mid-1;}elseif(nums[mid]===target){right=mid-1;}}if(left>=nums.length||nums[left]!=target){return-1;}returnleft;}

方式一的搜索区间为[left, right)。我们方式二的搜索区间改为[left, right]左闭右闭。因为right的取值为nums.length - 1是nums的最后一个值。while的终止条件则为left == right + 1,也就是代码中用的<=。

此时right = mid - 1而不是right = mid, 因为搜索区间变了,[left,right]两边都闭。

最后判断一下边界条件,如果left >= nums.length说明已经超出了搜索区间,或者呢left的值和target不一样说明没找到。

这样就和第⼀种⼆分搜索算法统⼀了,都是两端都闭的搜索区间,⽽且最后返回的也是left 变量的值。不过我还是比较倾向于这种。哈哈。

寻找最右侧满足条件的值方式一functionrightBound(nums,target){letleft=0;letright=nums.length;while(left<right){constmid=Math.floor(left+(right-left)/2);if(nums[mid]===target){left=mid+1;}elseif(nums[mid]<target){left=mid+1;}elseif(nums[mid]>target){right=mid;}}if(left===0)return-1;returnnums[left+1]===target?left-1:-1;}

这种方式和寻找左侧边界类似,还是使用搜索区间为[left, right)左闭右开的方式。关键的点在于当nums[mid]=== target的时候,设置的是left=mid+1。这样就可以把搜索区间变为[mid+1, right)。利用这种方式不断的增大左边界left的值,是的区间不断的向右靠拢,最后到达右边界。

但是这种方式最后返回的是left - 1。因为while的终止条件是left === right ,此时循环已经退出,如果已经找到了,那么left的则比要锁定的目标索引多1。因为下面这段代码

if(nums[mid]===target){left=mid+1}

所以最后的目标值要left - 1

方式二functionrightBound(nums,target){letleft=0;letright=nums.length-1;while(left<=right){constmid=Math.floor(left+(right-left)/2);if(nums[mid]===target){left=mid+1;}elseif(nums[mid]<target){left=mid+1;}elseif(nums[mid]>target){right=mid-1;}}if(right<0||nums[right]!==target){return-1;}returnright;}

这里和类似左侧边界的搜索区间[left, right]左闭右闭。

关于“JavaScript中的二分查找法怎么使用”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识,可以关注行业资讯频道,小编每天都会为大家更新不同的知识点。

域名注册
购买VPS主机

您或许对下面这些文章有兴趣:                    本月吐槽辛苦排行榜

看贴要回贴有N种理由!看帖不回贴的后果你懂得的!


评论内容 (*必填):
(Ctrl + Enter提交)   

部落快速搜索栏

各类专题梳理

网站导航栏

X
返回顶部