35 搜索插入位置(2021-04-27)

35. 搜索插入位置

链接:https://leetcode-cn.com/problems/search-insert-position/

题目描述见链接内容。

解法1:暴力解法

因为数组是有序的,直接暴力遍历就好,找到第一个大于等于target的元素,返回下标即可,如果没有找到,就返回数组长度

var searchInsert = function (nums, target) {
  const length = nums.length;

  for (let i = 0; i < length; i++) {
    if (nums[i] >= target) {
      return i;
    }
  }
  return length;
};
  • 时间复杂度:${O(N)}$
  • 空间复杂度:${O(1)}$
  • 执行结果:耗时76ms,击败了JavaScript的92%用户,内存消耗38.6MB,击败了84%的用户

解法2:二分法

暴力解法虽然爽,但是题目的两个特点:1数组有序;2查找某个元素,如果算法感觉敏感的话,应该立刻想到二分法,结果看了题解才想到二分法,而且自己还绊绊磕磕写不出来,正好这道题目的评论下面有人总结了二分法的笔记,趁这个机会单独学习、练习一下二分法

回到这道题目,我们要找到的其实就是第一个大于等于target的下标,这个下标的成立条件是:

nums[pos- 1] < target <= nums[pos]

所以在发现midVal大于target是,就更新result值,直到循环结束,result就是满足上述条件的下标

var searchInsert = function (nums, target) {
  const length = nums.length;

  let min = 0,
    max = length - 1,
    result = length;

  while (min <= max) {
    const midIndex = ~~((min + max) / 2);
    const midVal = nums[midIndex];
    if (midVal === target) {
      return midIndex;
    }
    if (midVal > target) {
      max = midIndex - 1;
      result = midIndex;
    } else {
      min = midIndex + 1;
    }
  }

  return result;
};
  • 时间复杂度:${O(log n)}$
  • 空间复杂度:${O(1)}$
  • 执行结果:耗时84ms,击败了JavaScript的63.90%用户,内存消耗38.9MB,击败了30.52%的用户

解法3:二分法优化

看了题解的评论,发现上面的解法可以优化,实际上result是不需要的,直接返回min就可以

因为根据if的判断条件,left左边的值都小于targetright右边的值都大于target,而且left最终一定等于right+1,循环结束后,在leftright之间画一条竖线,把数组分为两个部分,left左边全小于targetright右边全都大于target,并且由于遍历结束后left等于right+1,所以right右边的部分,并且以left为首,所以答案是left

为什么left一定等于right+1,因为每次循环至少会把[left, right]区间长度减少1,当l === r时, mid === l === r,如果target > nums[l]l就会向右移动一位l = mid + 1,如果target <= nums[l],那么r就会向左移动一位r = mid - 1,结果一样

因为while的判断条件是l <= r,如果l不大于r会是死循环

var searchInsert = function (nums, target) {
  const length = nums.length;

  let min = 0,
    max = length - 1;

  while (min <= max) {
    const midIndex = ~~((min + max) / 2);
    const midVal = nums[midIndex];
    if (midVal === target) {
      return midIndex;
    }
    if (midVal > target) {
      max = midIndex - 1;
    } else {
      min = midIndex + 1;
    }
  }

  return min;
};
  • 时间复杂度:${O(log n)}$
  • 空间复杂度:${O(1)}$
  • 执行结果:耗时84ms,击败了JavaScript的80.98%用户,内存消耗38.9MB,击败了30.52%的用户

感想

看了一个人的评论,二分法思想很简单,但是细节是魔鬼,确实感觉如此,大致思路知道,但是边界条件仔细思考起来一堆的问题,确实需要针对性的练习巩固一下二分法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值