704. 二分查找
首先明确题目给出的是有序且无重复元素的数组,这是使用二分法的前提。
题目唯一的难点就在于划分区间时边界条件的处理,遇到处理区间问题时此前一直的做法就是先把边界写好,至于边界点是否考虑在内再去带入数据验证,或者记住一套固定模板,没什么效率和固定的思路可言。
题解中提供了很好的结题思路,划分区间时停止循环的条件分两种情况来考虑。
- 第一种考虑方式,target是在一个闭区间
[left, right]
里,此时left == right
是有意义的(存在左右边界相等的情况),循环条件设定为left <= right
,这种情况下if (target < nums[mid])
时,right赋值为mid - 1
(已经判断过这一轮循环里nums[middle] != target
) 。
相应代码如下:
class Solution {
public int search(int[] nums, int target) {
int left = 0, right = nums.length - 1;
//假定区间为[left, right]
while (left <= right) {
//[left, right], left == right为合法情况
int mid = left + (right - left) /2;
//为防止两个int型变量相加溢出,本质上等价于(left + right) / 2
if (target < nums[mid]) right = mid - 1;
//target在左区间中 --> [left, mid - 1]
else if (target > nums[mid]) left = mid + 1;
//target在右区间中 -->[mid + 1, right]
else return mid;
//找到目标值,返回索引
}
return -1;
//未找到目标值
}
}
- 第二种考虑方式,target是在一个左闭右开区间
[left, right)
里,此时left = right
没有意义(左端点一定小于右端点),循环条件设定为left < right
,这种情况下if (target < nums[mid])
时,right
赋值为mid
(已经判断过这一轮循环里nums[middle] != target
,但是寻找区间是左闭右开,所以right
更新为mid
,而在下一轮寻找时不会再比较mid对应的位置) 。
相应代码如下:
class Solution {
public int search(int[] nums, int target) {
int left = 0, right = nums.length;
//注意,right初值要设定为 数组最大索引+1,否则会漏掉右边界元素
while (left < right) {
//如果 left == right, 区间[left, right)无效,所以不能取等
int mid = left + (right - left) /2;
if (target < nums[mid]) right = mid;
//target在区间[left, mid)中
else if (target > nums[mid]) left = mid + 1;
else return mid;
}
return -1;
}
}
参考文章链接:
代码随想录_704.二分查找
27. 移除元素
数组原地进行元素删除,不能简单的把元素删除理解为单独删掉某个元素,因为数组的在内存中连续存储的特性,每删除一个中间元素,需要把后续的元素往前移;后续元素覆盖中间元素并整体前移的操作即为删除某一中间元素。
那么在遍历数组时,如果与目标值val
不相等,如何确定该元素移动位置呢?
- 如果考虑暴力求解,思路则非常简单,每删除一个元素那么后续所有元素整体向前移动一位。带来的问题就是时间复杂度较高为 O ( n 2 ) O(n^2) O(n2)
- 面对这种情况,一般考虑使用快慢双指针实现。快指针
fastIndex
用来对原数组整体遍历,并进行判断是否和目标值val
相等,而慢指针sloowIndex
则负责实现保留新数组元素。- 如果
fastIndex
指向的元素不等于val,则该元素一定是新数组中的一个元素,把它复制到lastIndex
指向的位置,且两个指针都要右移 - 如果
fastIndex
指向的元素等于val,则该元素需要删除,左指针slowIndex
不动,右指针fastIndex
右移一位(该元素会在后续slowIndex
指向时,被新复制的元素覆盖,或新数组的下标到不了该位置,故右指针直接后移,无需处理)
- 如果
相应代码如下:
class Solution {
public int removeElement(int[] nums, int val) {
int slowIndex = 0;
for (int fastIndex = 0; fastIndex < nums.length; fastIndex++) {
if (nums[fastIndex] != val) {
nums[slowIndex++] = nums[fastIndex];
}
}
return slowIndex;
}
}
参考文章链接:
代码随想录_27.移除元素