小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
学习算法时, 要从简单的入手, 不断练手, 逐个突破
二分法
二分法 在面试中也会经常遇到的 手写算法, 要求我们要完整的手写出来, 并且无误! 来写一个二分搜索
二分法 有普通二分查找, 也有更高难度二分变种法. 二分法 通过不断地比较操作缩小问题的范围, 从而找到最终的答案, 这也是 分治思想的体现.
小栗子 LeetCode 167
今天刷到 LeetCode
第 167题
: 整型有序数组, 查找两数之和为 target
的索引值.
这里可用暴力循环法
, 直接遍历, 当然作为程序猿, 这不是优雅的解题方法. 看到这里的关键词 有序 我们就要想到 二分法
啦!
题目描述:
- 两数之和 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. 有序, 我们就想到了二分搜索
这里也是用到了 对撞指针
-
先看下执行时间 及结果
-
解题代码:
/**
* @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]
}
}
复制代码
思考
二分法通常用在有序数组这类结构的查找中. 当涉及到关键词 有序 或 查找 时, 我们可以利用二分法来想一下解决方案. 利用元素的关联, 来逐渐缩小问题的规模.