一、LeetCode704.二分查找
阅题思路:《2022年王道数据结构考研复习指导》,如下图:
看了随想录的笔记后,现在意识到这个方法属于左闭右闭;
步骤拆解:
代码如下:
private static int binarySearch(int[] nums, int target) {
int length = nums.length;
int left = 0;
int right = length-1;
while (left <= right) {
int mid = (left + right) / 2;
if (nums[mid] == target) {
return mid;
} else if (nums[mid] > target) {
// 查找区间中间值大于目标值
// 移动右指针,去左区间查询
right = mid - 1;
} else if (nums[mid] < target) {
left = mid + 1;
}
}
return -1;
}
二、LeetCode35.搜索插入位置
阅题思路:首先肯定是使用二分法(题目中要求时间复杂度为O(log n));和704不同的是,如果没有找到,需要返回它将会被按顺序插入的位置。
步骤拆解:
代码如下:
public int searchInsert(int[] nums, int target) {
int length = nums.length;
int left = 0;
int right = length - 1;
while (left <= right) {
int mid = (left + right) / 2;
if (nums[mid] == target) {
return mid;
} else if (nums[mid] < target) {
// 当前查找到的值小于目标值,左指针移位,去右区间查询
left = mid + 1;
} else if (nums[mid] > target) {
// 当前查找到的值大于目标值,右指针移位,去左区间查询
right = mid - 1;
}
}
// 可以退出循环说明没有查找到目标值,这个时候插入位置就是right + 1;
return right + 1;
}
三、LeetCode34.在排序数组中查找元素的第一个和最后一个位置
阅题思路:使用两次二分查找进行搜索。
做题困难:首先是对于三种情况的区分,这点是看了随想录才知道三种情况对应题目的三个示例;其次是关于左边界和右边界查询时的判断,还是有点儿模糊,每次需要手写演算。
步骤拆解:
寻找右边界是同理的,只不过移动的是left左指针。
代码如下:
class Solution {
public int[] searchRange(int[] nums, int target) {
int leftBorder = getLeftBorder(nums, target);
int rightBorder = getRightBorder(nums, target);
// 三种情况
// 情况一: target在数组范围的左右
if (rightBorder == -2 || leftBorder == -2) {
return new int[]{-1, -1};
}
// 情况三: target在数组范围中且target存在
if ((rightBorder - leftBorder) > 1) {
// 因为找到的话,右边界肯定是大于左边界的
return new int[]{leftBorder + 1, rightBorder - 1};
}
// 情况二: target在数组范围,但是数组不存在target
return new int[]{-1, -1};
}
public static int getLeftBorder(int[] nums, int target) {
int length = nums.length;
int left = 0;
int rigt = length - 1;
// 给左边界附上初值,保障情况一;
int leftBorder = -2;
while (left <= rigt) {
int mid = (left + rigt) / 2;
// 寻找左边界移动的其实是right指针;
// 所以要保证当nums[mid] == target的时候也需要移动,否则就找不到最左边界了;
if (nums[mid] >= target) {
rigt = mid - 1;
leftBorder = rigt;
} else {
// 移动left
left = mid + 1;
}
}
return leftBorder;
}
public static int getRightBorder(int[] nums, int target) {
int length = nums.length;
int left = 0;
int right = length - 1;
// 给右边界附上初值,保障情况一;
int rightBorder = -2;
while (left <= right) {
int mid = (left + right) / 2;
// 寻找右边界移动的其实是left指针;
if (nums[mid] > target) {
right = mid - 1;
} else {
left = mid + 1;
rightBorder = left;
}
}
return rightBorder;
}
}
备注:此题过度依赖《代码随想录》,需要二刷。
四、LeetCode27.移除元素
阅题思路:这道题在看到的时候是没有思路的(此前第一次做的时候,现在能想到是快慢指针的方法),直接去看了讲解;
步骤拆解:
代码如下:
public int removeElement(int[] nums, int val) {
// 定义慢指针
int slow = 0;
for (int fast = 0; fast < nums.length; fast++) {
if (nums[fast] != val) {
// 值不相等的时候就可以给慢指针指向的位置赋值
nums[slow] = nums[fast];
// 快慢指针同时移动
slow++;
}
}
return slow;
}