Appearance
01. 二分搜索篇
TIP
二分搜索,又称折半查找,一种在有序数组中查找目标元素的搜索算法。 所以下面代码中的 nums
都假定已经从小到大排好序了。
1. 基础二分搜索
js
const searchInsert = function (nums, target) {
let low = 0, high = nums.length - 1
while (low <= high) {
let mid = (low + high) >> 1
if (nums[mid] === target) {
return mid
}
if (nums[mid] < target) {
low = mid + 1
} else {
high = mid - 1
}
}
return -1
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2. 查找插入位置
只需修改基础版本的一行代码。
ts
function searchInsert(nums: number[], target: number): number {
let [low, high] = [0, nums.length - 1]
while (low <= high) {
const mid = (low + high) >> 1
if (nums[mid] === target) return mid
if (nums[mid] > target) high = mid - 1
else low = mid + 1
}
return low // 相比于基础二分搜索,这里返回的是插入位置
}
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
3. 查找左边界
TIP
所谓查找左边界,就是在数组中查找最左边位置的目标元素。例如在 [-1, 1, 1, 1, 2]
中查找 1
,应该返回下标 1
。
js
// 寻找左边界
const getLeftBorder = (nums, target) => {
let l = 0, r = nums.length - 1
while (l <= r) {
let mid = l + Math.floor((r - l) / 2)
if (nums[mid] === target) {
// 把右范围 r 一直向左逼近,直到到达 target 的左边界
r = mid - 1
} else if (nums[mid] < target) {
l = mid + 1
} else {
r = mid - 1
}
}
// 1、若 target 大于数组中所有元素,则 l 一直右移,最后 l>=nums.length
// 2、若 target 小于数组中所有元素,则 l = 0;
// 3、剩下一种情况是 target 在 nums 中,结合2、3则判断 nums[l] !== target
if (l >= nums.length || nums[l] !== target) {
// 不存在 target
return -1
}
return l
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
4. 查找右边界
TIP
所谓查找右边界,就是在数组中查找最右边位置的目标元素。例如在 [-1, 1, 1, 1, 2]
中查找 1
,应该返回下标 3
。
js
// 寻找右边界
const getRightBorder = (nums, target) => {
let l = 0, r = nums.length - 1, mid = 0
while (l <= r) {
mid = l + Math.floor((r - l) / 2)
if (nums[mid] === target) {
// 把左边范围 l 往右边逼近,直到到达 target 的右边界
l = mid + 1
} else if (nums[mid] < target) {
l = mid + 1
} else {
r = mid - 1
}
}
// 1、若 target 小于数组中所有元素,则 r 一直左移,最后 r<0
// 2、若 target 大于数组中所有元素,则 r = nums.length-1;
// 3、剩下一种情况是 target 在 nums 中,结合2、3则判断 nums[r] !== target
if (r < 0 || nums[r] !== target) {
// 不存在 target
return -1
}
return r
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
5. 二分法求平方根
时间复杂度为 O(log(x))
的算法。
ts
function mySqrt(x: number): number {
if (x === 1) return 1
let [min, max] = [0, x]
while (max - min > 1) {
let mid = Math.floor((max + min) / 2)
if (mid > x / mid) {
max = mid
} else {
min = mid
}
}
return min
}
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13