【乱杀图解算法】704. 二分查找

80 阅读2分钟

题意

题目链接

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

示例 1:

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

这个题啊,有一说一,不知不觉做了三遍,这三遍的解法都不一样

第一次解,小白做法,直接for循环暴力查找

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number} */
var search = function (nums, target) {
    if (nums.indexOf(target) !== -1) {
        for (let i = 0; i < nums.length; i++) {
            if (nums[i] === target)
                return i
        }
    }
    return -1
};

第二次,用的二分查找

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number}
 */
var search = function(nums, target) {
    var upperBound=nums.length-1;
    var lowerBound=0;
    while(lowerBound<=upperBound){
        var mid = Math.floor((upperBound+lowerBound)/2);
        if(nums[mid]<target){
            lowerBound = mid + 1;
        }else if(nums[mid]>target){
            upperBound = mid - 1;
        }else{
            return mid
        }
    }
    return -1
};

第三次,就一行代码(对数组一些API用得比较熟悉了)

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number}
 */
var search = function(nums, target) {
    return nums.findIndex(item=>item===target);
};

但是我们可以看到,这三遍下来时间复杂度最低的还是二分查找

image.png

所以这边重点来分析一下 二分查找

概念

啥叫二分查找?

简单来说,就是一分为二

一个图给你整明白了。哦不,这是我自己的图,给我整明白了。

你们不明白,就去看这个

aa6236def6726c4a6572c85da211cde.png

拿mid和target做对比,不断缩小区间的同时,mid也是在改变的,直到mid===target

前置条件

满足用二分查找的前提条件:

  1. 有序数组

  2. 无重复元素

解释下上面俩前置条件是为啥:

有序数组是因为,当我们用二分查找需要用到一个判断条件叫left<=right

没有重复元素其实也不算特别必要的条件,只是说,如果存在重复元素的话,最终可能会出现多个满足target的index,这样的话,题目就是另外一回事儿了

思想

主要目的是掌握 二分查找 的思想

我们这个二分查找,是基于数组的基础去理解的,数组我们知道,它的内存空间是连续的,只要我们想要查找一个数组中的元素,那我们每一次查找都需要遍历一遍数组,它的 时间复杂度是O(n)

那么二分呢,二分查找肯定是基于数组的对吧

二分相当于遍历的那个次数折半了,所以它的时间复杂度是O(log2n)

它比起普通的for循环遍历,效率要高不少,不过第三种解法,代码真的少很多啊!!!

以后如果侧重考虑性能问题,还是写二分查找,不然我其实emm还是更喜欢第三种哈哈哈