8. <tag-数组和二分查找_1>-lt.704-二分查找 + lt.33-搜索旋转排序数组 +lt.34-在排序数组中查找元素的第一个和最后一个位置 + lt.35-搜索插入位置 2.3
lt.704 二分查找
[案例需求]
[思路分析]
- 二分法典型例题, 有什么好说的, 我秒了(误)
- 口误啊口误, 可不敢说秒二分. 本题是二分法的标准入门题, 本意还是通过二分查找值, 是前面讲过的二分查找的第一个模板, 在这里就不讲太多了, 好好看下前面文章哈.
[代码实现]
class Solution {
public int search(int[] nums, int target) {
// // 左开右闭
// int left = 0;
// int right = nums.length;
// while(left < right){
// int mid = left + (right - left)/2;
// if(nums[mid] == target){
// return mid;
// }else if(nums[mid] < target){
// left = mid + 1;
// }else if(nums[mid] > target){
// right = mid;
// }
// }
//二分查找, 左闭右闭
int left = 0;
int right = nums.length - 1;
while(left <= right){
int mid = left + (right - left)/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;
}
}
lt.33-搜索旋转排序数组
[案例需求]
[思路分析]
将数组一分为二,其中一定有一个是有序的,另一个可能是有序,也能是部分有序。
此时有序部分用二分法查找。无序部分再一分为二,其中一个一定有序,另一个可能有序,可能无序。就这样循环.
[代码实现]
class Solution {
public int search(int[] nums, int target) {
//数组局部有序 + 不重复, 考虑用二分查找
int left = 0;
int right = nums.length - 1;
while(left <= right){
int mid = left + (right - left)/2;
//跳出遍历的出口
if(nums[mid] == target) return mid;
//遍历部分有序的序列, 对这部分有序的序列进行二分查找
//在有序的左半段(nums[left] < nums[mid])
if(nums[left] <= nums[mid]){
//缩小左半段的边界(左半段的左边界), 去除组织这个序列单调的数
if(nums[left] <= target && nums[mid] > target){
right = mid - 1; //左半段的单调序列
}else{
left = mid + 1; //右半段的单调序列
}
}else{ //右半段有序的序列
//缩小右边届的左半段
if(nums[mid] < target && nums[right] >= target){
left = mid + 1; //右半段的单调序列
}else{
right = mid - 1;//左半段的单调序列
}
}
}
return -1;
}
}
lt.34-在排序数组中查找元素的第一个和最后一个位置
[案例需求]
[思路分析]
- 一个二分方法向左查找第一个位置
- 另一个二分查找向右查找第二个位置
- 根据题意, 在找到nums[mid] == target位置时,应该继续向左或向右移动指针, 而不是直接返回mid了
如何判断和移动是比较需要记住的一点:
这里我们拿向左寻找第一个target, 并找到的条件下 作为示例:
if(nums[mid] == target){
if(mid == 0 || nums[mid] != nums[mid - 1]){ //mid到达了序列的第一个数, 或者前面已经没有相同的数
return mid; // mid一定存在, 因为上面的判断条件是 nums[mid] == target!!!
}else{
mid = mid - 1;
}
}
[代码实现]
class Solution {
public int[] searchRange(int[] nums, int target) {
int leftIndex = findLeft(nums, target);
int rightIndex = findRight(nums, target);
return new int[]{leftIndex, rightIndex};
}
public int findLeft(int[] nums, int target){
int left = 0;
int right = nums.length - 1;
int leftIndex = -1;
while(left <= right){
int mid = left + ((right - left) >> 1);
if(nums[mid] == target){
leftIndex = mid;
right = mid - 1;
}else if(nums[mid] > target){
right = mid - 1;
}else{
left = mid + 1;
}
}
return leftIndex;
}
public int findRight(int[] nums, int target){
int left = 0;
int right = nums.length - 1;
int rightIndex = -1;
while(left <= right){
int mid = left + ((right - left) >> 1);
if(nums[mid] == target){
rightIndex = mid;
left = mid + 1;
}else if(nums[mid] > target){
right = mid - 1;
}else{
left = mid + 1;
}
}
return rightIndex;
}
}
原先的解法:
class Solution {
public int[] searchRange(int[] nums, int target) {
// 要求 o(logn), 并且是有序序列, 二分法走起
//特例
if(nums.length == 0) return new int[]{-1,-1};
//左边界和右边界,
return new int[]{bsfirst(nums, target), bslast(nums, target)};
}
public int bsfirst(int[] nums, int target){
int left = 0;
int right = nums.length - 1;
while(left <= right){
int mid = left + ((right - left) >> 1);
if(nums[mid] > target){
right = mid - 1;
}else if(nums[mid] < target){
left = mid + 1;
}else if(nums[mid] == target){
///
if(mid == 0 || nums[mid - 1] != target){
return mid;
}else{
right = mid - 1;
}
}
}
return -1;
}
public int bslast(int[] nums, int target){
int left = 0;
int right = nums.length - 1;
while(left <= right){
int mid = left + ((right - left) /2);
if(nums[mid] > target){
right = mid - 1;
}else if(nums[mid] < target){
left = mid + 1;
}else if(nums[mid] == target){
if(mid == nums.length - 1 || nums[mid + 1] != target){
return mid;
}else{
left = mid + 1;
}
}
}
return -1;
}
}
lt.35-搜索插入位置
[案例需求]
[思路分析]
- 比较常规的二分查找, 找到目标值直接返回索引即可;
- 当未找到目标值时, 此时
left > right ( left + 1 = right)
, 由于题目要求返回的是目标值应该插入的位置, 而我们在比较nums[mid] 和 target值时, 最后一次比较应该是 left == right的时候; - 而最后一次while(left == right)内的比较都没有找到, 在这最后一次比较完成后, left > right, 所以要求的返回target值应该插入的位置 (即第一个比target值大的值所在的索引), 理应返回的是left 而不是right;
[代码实现]
class Solution {
public int searchInsert(int[] nums, int target) {
// //logn 二分
// int left = 0;
// int right = nums.length - 1;
// int mid = 0;
// while(left <= right){
// mid = left + (right - left)/2;
// if(nums[mid] == target){
// return mid;
// }else if(nums[mid] > target){
// right = mid - 1;
// }else if(nums[mid] < target){
// left = mid + 1;
// }
// }
// return left;
// }
int left = 0;
int right = nums.length -1;
while(left <= right){
int mid = left + ((right - left) /2);
if(nums[mid] == target){
return mid;
}else if(nums[mid] > target){
right = mid - 1;
}else if(nums[mid] < target){
left = mid + 1;
}
}
return left;
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)