LeetCode之起始:二分查找算法
今天开始自己的LeetCode之旅,首先当然是要从最基础的二分查找算法开始入门了。
写在前面
本文章是本人的第一篇博文,在各方面可能都有需要完善的地方,还请大牛们看到忽略。适用于和我一样刚接触算法的小白阅读。
题目
题目:给定一个 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
链接:https://leetcode-cn.com/problems/binary-search
思考
首先拿到这道题的时候,相信绝大多数同学脑子里面的第一个想法就是强行遍历。算法如下:
(由于本人使用的编程语言是Java,所以所有案例代码都是以java进行演示的)
public class search(int[] nums,int target){
for(int i = 0;i<nums.length;i++){
if(result[i]==target){
return i;
}
}
return -1;
}
初看这段代码可能会觉得没有任何问题,但是仔细观察,这段代码的时间复杂度是O(n),也就是说最不理想的情况下,target刚好在数组的最后一个位置,那么就需要遍历n次才能够找到目标值,假设数组的大小达到万级,那么这个算法的是相当不理想的。
二分查找
二分查找又叫折半查找,是一种基于比较目标值和数组中间元素的教科书式算法。
从简单来讲其核心可以概括为三个内容:
1.当目标值等于中间元素的时候,该元素的索引值就是我们要找的下标。
2.当目标值大于中间元素的时候,说明该目标值位于中间元素的右侧。
3.当目标值小于中间元素的时候,说明该目标值位于中间元素的左侧。
它充分利用了元素间的次序关系,采用分治策略,可在最坏的情况下用O(log n)完成搜索任务。它的核心思想是:将包含n个元素的数组分成个数大致相同的两半,取nums[n/2]与目标值x进行比较,假如相同,算法结束;假如x<a[n/2],那我们只需要在nums的左半区域继续搜索目标值x即可;如果x>a[n/2],那我们只需要在nums的右半区域继续搜索目标值x即可,每次查找都是对折而不需要遍历整个数组。
算法实现
实现过程包括以下步骤:
1.初始化左指针left = 0 以及右指针right = nums.length-1;
2.初始化中间的元素的下标值 index = (left + right)/2;
3,当左指针一直小于右指针的时候,不断地对目标值以及中间元素进行比较。
(1) 假如target = nums[index],则返回index;
(2) 假如 target < nums[index],说明目标值在中间元素的左侧,则需要让right = index - 1;
(3) 假如 target > nums[index],说明目标值在中间元素的右侧,则需要让left = index + 1;
代码实现
具体代码如下:
class Solution {
public int search(int[] nums, int target) {
int index , left = 0, right = nums.length - 1;
while(left <= right){
index = (left + right)/2;
if(nums[index]==target) return index;
if(target<nums[index]){
right = index - 1;
}else{
left = index + 1;
}
}
return -1;
}
}
使用该算法后,从时间复杂度或者是空间复杂度上来讲相比于一开始的算法都有了很高的提升。建议对于该算法不是特别理解的同学,可以动手画一下该算法的实现过程,就能够马上领悟其中的精髓了。
局限性
二分查找的使用具有一定的局限性,需要满足以下两个条件才能考虑使用该算法:
1,必须采用保证顺序存储结构来存储元素。
2,元素必须按关键字大小有序排列。
其中某一个条件不满足都不可使用二分查找算法。好奇的同学可以自己尝试下其中某一个不符合的情况。