算法学习从简单入手-二分法-LeetCode167

327 阅读3分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

本文已参与「掘力星计划」,赢取创作大礼包,挑战创作激励金。

学习算法时, 要从简单的入手, 不断练手, 逐个突破

二分法

二分法 在面试中也会经常遇到的 手写算法, 要求我们要完整的手写出来, 并且无误! 来写一个二分搜索

二分法 有普通二分查找, 也有更高难度二分变种法. 二分法 通过不断地比较操作缩小问题的范围, 从而找到最终的答案, 这也是 分治思想的体现.

小栗子 LeetCode 167

今天刷到 LeetCode167题: 整型有序数组, 查找两数之和为 target 的索引值.

这里可用暴力循环法, 直接遍历, 当然作为程序猿, 这不是优雅的解题方法. 看到这里的关键词 有序 我们就要想到 二分法 啦!

题目描述:

  1. 两数之和 II - 输入有序数组

给定一个已按照 非递减顺序排列   的整数数组  numbers ,请你从数组中找出两个数满足相加之和等于目标数  target 。 函数应该以长度为 2 的整数数组的形式返回这两个数的下标值。numbers 的下标 从 1 开始计数 ,所以答案数组应当满足 1 <= answer[0] < answer[1] <= numbers.length

你可以假设每个输入 只对应唯一的答案 ,而且你 不可以 重复使用相同的元素。

示例 1: 输入: numbers = [2,7,11,15], target = 9 输出:[1,2] 解释:2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2

这里需要我们注意的是:

  • 要返回是目标元素的索引, 而不是下标. 索引从 1 开始, 而下标从 0 开始

面试的时候可能没有上面描述这么完整, 在面试中要和面试官确认下一些问题

  • 没有解的时候怎么办? 保证有解
  • 有多个解呢?
  • 返回任意解? 对返回顺序有要求吗?

题解思路分析:

1. 直接暴力解法:

双层遍历: 先解决问题, 后面再优化(但是在 LeetCode 上应该会超时!); 这种方法也没有用到题目中的 有序 这一特征 复杂度: O(n^2)

2. 有序, 我们就想到了二分搜索

这里也是用到了 对撞指针

  • 先看下执行时间 及结果 image

  • 解题代码:

/**
 * @param {number[]} numbers
 * @param {number} target
 * @return {number[]}
 */
var twoSum = function (numbers, target) {
  let l = 0,
    r = numbers.length - 1 // 定义两个指针 从数组两端向中间挤(查找)
  while (l < r) {
    // 这里的细节 能不能等于?
    let m = numbers[l] + numbers[r]
    if (m > target) {
      r--
    }
    if (m < target) {
      l++
    }
    if (m === target) return [l + 1, r + 1]
  }
}

思考

二分法通常用在有序数组这类结构的查找中. 当涉及到关键词 有序查找 时, 我们可以利用二分法来想一下解决方案. 利用元素的关联, 来逐渐缩小问题的规模.

参考