【面试-leetcode35】搜索插入位置(顺序查找+二分查找)

80 阅读2分钟

freysteinn-g-jonsson-s94zCnADcUs-unsplash.jpg

这是leetcode面试刷题一题多解系列的第三篇,今天给大家来一个简单点的,练习下在数组有序的情况下最常用的提升性能的查找方法,二分查找。

题目

今天跟大家一起看一道经典的二分查找的算法题,搜索插入位置。

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。

来源:力扣(LeetCode)
链接:leetcode.cn/problems/se…
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

题解1---顺序查找

这是这道题最简单也是最直接的一种思路,既然数组有序,那么就顺序去查找,最差情况遍历一遍数组的所有数据项。时间复杂度是 O(N),空间复杂度 O(1)。

var searchInsert = function (nums, target) {
  for (let i = 0; i < nums.length; i++) {
    if (nums[i] >= target) {
      return i;
    }
  }
  return nums.length;
};

题解3--二分法查找

二分法的基本思想是将待查找区间一分为二,然后判断待查找元素在哪个子区间中,再将该子区间作为新的待查找区间,重复以上步骤,直到找到该元素或确定该元素不存在为止。由于每次查找都将待查找区间缩小一半,因此这种算法的时间复杂度为O(logN),比线性查找的O(N)要快很多,空间复杂度O(1)。

 var searchInsert = function(nums, target) {
  const n = nums.length;
  // left和right分别为区间的左右边界,ans的初始值为n(即整个数组的最后)
  let left = 0, right = n - 1, ans = n;
  // 循环条件,保证所有数据项都被考虑
  while (left <= right) {
     // 求得区间中间位置索引
      let mid = ((right - left) >> 1) + left;
      // 在左半区间
      if (target <= nums[mid]) { 
          ans = mid;
          right = mid - 1;
      } else {
          // 右半区间
          left = mid + 1;
      }
  }
  return ans;
};

初始化变量n为数组nums的长度,left为0,right为n-1,ans为n。其中ans表示插入元素在nums中的位置,如果target已经存在于nums中,则ans为其在nums中的下标;如果target不存在于nums中,则ans为插入target后nums仍然保持有序的位置,其中mid = ((right - left) >> 1) + left ,表示待查找区间的中间位置,计算mid的常见方式是将待查找区间的左右边界相加再除以2。但是,这种计算方式可能会在边界比较大的情况下出现整型溢出的问题,所以采用了相减的方式,>> 是位运算符,相当于除以2的指数次方。

二分法的优点主要有两点,其一是时间复杂度较低,特别在数据规模较大的情况下,二分法的优势会非常明显;其二是适用范围广,除了有序数组外,二分法还适用于数值单调性的问题,比如找到满足某个条件的最大/最小整数,二分法虽然简单,但是在一些有序,数据具有单调性的情况下常常会发挥出意想不到的优势。