704. 二分查找
/**
* @param {number[]} nums
* @param {number} target
* @return {number}
*/
var search = function (nums, target) {
let middle, left = 0;
let right = nums.length - 1;
while (left <= right) {
middle = Math.floor((left + right) / 2);
if (nums[middle] === target) {
return middle;
} else if (nums[middle] > target) {
right = middle - 1;
} else left = middle + 1;
}
return -1;
};
通过定义左右指针 left 和 right ,计算中间指针 middle 来逐步缩小查找范围。
如果中间元素 nums[middle] 等于目标值 target ,则返回中间索引。
如果中间元素大于目标值,将右指针更新为 middle - 1 。
如果中间元素小于目标值,将左指针更新为 middle + 1 。
如果在整个查找过程中都未找到目标值,返回 -1 。
Tips: 定义 target 是在一个在左闭右闭的区间里,也就是[left, right] (这个很重要非常重要) 。
区间的定义这就决定了二分法的代码应该如何写,因为定义target在[left, right]区间,所以有如下两点:
- while (left <= right) 要使用 <= ,因为left == right是有意义的,所以使用 <=
- if (nums[middle] > target) right 要赋值为 middle - 1,因为当前这个nums[middle]一定不是target,那么接下来要查找的左区间结束下标位置就是 middle - 1
27. 移除元素(双指针)
/**
* @param {number[]} nums
* @param {number} val
* @return {number}
*/
var removeElement = function (nums, val) {
let slow = 0;
for (let fast = 0, len = nums.length; fast < len; fast++) {
if (nums[fast] !== val) {
nums[slow++] = nums[fast];
}
}
return slow;
};
- 初始化指针:在函数内部,首先初始化了两个指针
slow和fast,分别表示慢指针和快指针。slow指针初始化为0,fast指针也初始化为0。同时,获取数组的长度len。 - 遍历数组:使用
for循环,fast指针从数组的第一个元素开始遍历,直到最后一个元素。 - 条件判断:在循环内部,使用
if语句判断当前fast指针所指向的元素是否不等于val。 - 移除元素:如果当前元素不等于
val,则将其赋值给nums[slow],并且slow指针向前移动一步。这实际上是将不等于val的元素复制到数组的左边。 - 忽略目标值:如果当前元素等于
val,则fast指针继续向前移动,而slow指针保持不变,这样等于val的元素就会被跳过,不会被复制到数组的左边。 - 返回结果:循环结束后,
nums数组中所有不等于val的元素都被复制到了数组的左边,slow指针指向的是最后一个不等于val的元素的下一个位置。返回slow,即移除了目标值val后的元素数量。
总的来说,这个算法使用了两个指针来遍历数组,一个指针用于复制元素,另一个指针用于跳过不需要的元素。这种算法的时间复杂度为 O(n),空间复杂度为 O(1),其中 n 是数组的长度。