【LeetCode】在排序数组中查找元素的第一个和最后一个位置【三次二分】

给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。

你的算法时间复杂度必须是 O(log n) 级别。

如果数组中不存在目标值,返回 [-1, -1]。

示例 1:

输入: nums = [5,7,7,8,8,10], target = 8
输出: [3,4]

示例 2:

输入: nums = [5,7,7,8,8,10], target = 6
输出: [-1,-1]

来源:力扣(LeetCode)
链接:
https://leetcode-cn.com/problems/find-first-and-last-position-of-element-in-sorted-array

分析:

数组有序,要求时间复杂度是O(log N),可以联想到二分

先直接在整个数组中二分找target,假设没有找到,那么返回[-1,-1]即可

假设找到了target,位置索引是k,那么在区间[0,k-1],[k+1,n-1]都进行二分寻找target

两个区间寻找target只有四种结果:

假设两个区间找到了target的索引为k1和k3,第一次找到的target索引为k2

1)第一个区间找到,第二个区间没有找到,返回结果:[k1,k2]

2)第一个区间找到,第二个区间找到,返回结果:[k1,k3]

3)第一个区间没有找到,第二个区间找到,返回结果:[k2,k3]

4)第一个区间没有找到,第二个区间没有找到,返回结果:[k2,k2]

总结:先进行一次二分寻找目标值是否存在,然后分别在目标值的两边进行两次二分寻找左右端点

总共三次二分

时间复杂度:O(log N)

空间复杂度:O(1)

复制代码
class Solution {
public:
    
//二分函数
int f(vector<int>& v,int l,int h,int t,int flag)
{
    int k1=INT_MAX;
    int k3=INT_MIN;
    while(l<=h)
    {
        int mid=(l+h)/2;
        if(v[mid]==t)
        {
            if(flag==1)
                k1=min(k1,mid);
            else if(flag==3)
                k3=max(k3,mid);
            else if(flag==2)
                return mid;
            if(v[l]==t)
            {
                k1=min(k1,l);
                k3=max(k3,l);
            }
            if(v[h]==t)
            {
                k1=min(k1,h);
                k3=max(k3,h);
            }
            l++;//找到了也要继续找下去
            h--;
        }
        else if(v[mid]>t)
        {
            h=mid-1;
        }
        else if(v[mid]<t)
        {
            l=mid+1;
        }
    }
    if(flag==1&&k1!=INT_MAX)
        return k1;
    if(flag==3&&k3!=INT_MIN)
        return k3;
    return -1;
}
vector<int> searchRange(vector<int>& v, int t)
{
    vector<int> ans;
    int n=v.size();
    int k2=f(v,0,n-1,t,2);//第一次二分判断target是否存在
    if(k2==-1)
    {
        ans.push_back(-1);
        ans.push_back(-1);
        return ans;
    }
    //在target的两端各自进行一次二分确定左右区间端点值
    int k1=f(v,0,k2-1,t,1);
    int k3=f(v,k2+1,n-1,t,3);
    
    //根据二分结果确定结果区间
    if(k1==-1)
        ans.push_back(k2);
    else
        ans.push_back(k1);
    if(k3==-1)
        ans.push_back(k2);
    else
        ans.push_back(k3);
    return ans;
}
};
复制代码
posted @   西*风  阅读(371)  评论(0编辑  收藏  举报
编辑推荐:
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
历史上的今天:
2018-08-19 POJ 2251 Dungeon Master(多层地图找最短路 经典bfs,6个方向)
2018-08-19 POJ 1321 棋盘问题(非常经典的dfs,入门题)
点击右上角即可分享
微信分享提示