打卡-算法训练营-Day1 | 704. 二分查找,27. 移除元素

85 阅读2分钟

二分查找

leetcode链接:leetcode.cn/problems/bi…

能使用二分查找的前提条件

  1. 有序数组
  2. 数组中没有重复的元素

二分查找代码的重难点

循环不变量,感觉这个从字面上不太好理解,可以直接先记左闭右闭,左闭右开 (之前刷过几道题目,记住了左闭右闭,左闭右开,但是没记住什么意思,不过可以推导出来)

左闭右闭 -> [left, right] -> 对应while循环里面的条件是 left <= right

左闭右开 -> [left, right) -> 对应while循环里面的条件是 left < right

理解了上面的区间,就好理解循环不变量(我自己感觉循环不变区间更容易理解点)

二分查找是一个区间一个区间的搜索,每次迭代区间都是固定的,要么都是左闭右闭,要么都是左闭右开

那么right和left变量的更新就可以根据选择的区间模式去写

左闭右闭 -> [left, right]

当 target < nums[mid] 时,需要更新right,下一个区间的right肯定是要在区间内的,但此时mid已经判断过了,不需要再放入下一个区间了,所以right = mid - 1;

当 target > nums[mid]时,需要更新left,下一个区间的left肯定是要在区间内的,但此时mid已经判断过了,不需要再放入下一个区间了,所以left = mid + 1;

代码贴一下,方便和文字进行理解

// 左闭右闭写法[left, right]
var search = function (nums, target) {
  const length = nums.length;
  if (length <= 0) return -1;

  // 最初的区间定义也要遵循选择的区间模式
  let left = 0;
  let right = length - 1;

  // left可以等于right,对应while循环的条件left <= right
  while (left <= right) {
    let mid = Math.floor((right - left) / 2) + left;
    if (target === nums[mid]) {
      return mid;
    } else if (target > nums[mid]) {
      left = mid + 1;
    } else {
      right = mid - 1;
    }
  }
  return -1;
};

左闭右开 -> [left, right)

target < nums[mid] 时,需要更新right,下一个区间的right是肯定不在区间内的,此时mid已经判断过了,符合不在区间内,所以right = mid;

target > nums[mid] 时,需要更新left,下一个区间的left是肯定在区间内的,此时mid已经判断过了,不需要再放入下一个区间了,所以left = mid + 1;

// 左闭右开写法[left,right)
var search = function (nums, target) {
  const length = nums.length;
  if (length <= 0) return -1;

  // 最初的区间定义也要遵循选择的区间模式
  let left = 0;
  let right = length;

  // left不可以等于right,对应while循环的条件left < right
  while (left < right) {
    let mid = Math.floor((right - left) / 2) + left;
    if (target === nums[mid]) {
      return mid;
    } else if (target > nums[mid]) {
      left = mid + 1;
    } else {
      right = mid;
    }
  }
  return -1;
};

双指针

leetcode链接:leetcode.cn/problems/re…

这道题目的重点和难点:要理解快指针和慢指针分别代表的作用

快指针:寻找符合新数组的元素

慢指针:更新新数组对应下标的元素

参考链接:

programmercarl.com/0704.%E4%BA…

programmercarl.com/0027.%E7%A7…