【Leetcode刷题随笔】34 在排序数组中查找元素的第一个和最后一个位置

1. 题目描述:

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

如果数组中不存在目标值target,则返回[-1, -1]。题目要求设计 时间复杂度为0(log n) 的算法来实现。原题链接:34 。

2. 解题思路

复杂度为0(log n)的算法,大家比较熟知的就是 二分查找算法 ,二分查找对于寻找数组中的目标元素也是比较高效,因此这题优先考虑二分查找。(对二分查找不了解的朋友可以先做一下 二分查找)。

这题要求找到目标元素的第一个索引和最后一个索引,因此我们可以用两遍二分查找法,第一遍寻找第一个,第二遍寻找第二个,这样实现的代码也很直观,易于理解。

同时,如果我们只想使用一遍二分查找法,也可以在找到第一个target之后直接向右遍历,直到找到最后一个target。

3.代码实现(C语言)

3.1 双二分查找方法实现

int* searchRange(int* nums, int numsSize, int target, int* returnSize) {
    *returnSize = 2;
    int* res = (int*)malloc(sizeof(int) * 2);//动态分配内存空间
    int left = 0, right = numsSize - 1; //定义左右边界
    int first = -1; //定义要返回的两个索引,初始化为-1
    int last = -1;
    //第一遍二分查找,寻找第一次出现时的索引
    while(left <= right){
        int mid = left + (right - left) / 2;
        if(nums[mid] == target){
            first = mid;
            right = mid - 1; 
            //(关键)如果找到了等于target的值,由于我们无法确定它是不是第一次出现
            // 所以将右边界左移,检查其左侧是否还有等于target的值,确保first等于第一次出现的索引
        }else if(nums[mid] > target){
            right = mid - 1;
        }else{
            left = mid + 1;
        }
    }
	
	//第二遍二分查找,寻找最后一次出现时的索引,原理和第一次二分查找是相同的,只是这次处理左边界
	//在上面时左右边界已被改变,所以这里重新定义
    left = 0;
    right = numsSize - 1;
    while(left <= right){
        int mid = left + (right - left) / 2;
        if(nums[mid] == target){
            last = mid;
            left = mid + 1;
        }else if(nums[mid] > target){
            right = mid - 1;
        }else{
            left = mid + 1;
        }
    }
    res[0] = first;
    res[1] = last;
    return res;
}

3.2 单二分查找方法实现

//前面部分和双二分查找是一样的,先找到target第一次出现时的索引first
int* searchRange(int* nums, int numsSize, int target, int* returnSize){
    *returnSize = 2;
    int* res = (int*)malloc(sizeof(int) * 2);
    int left = 0;
    int right = numsSize - 1;
    int first = -1, last = -1;
    while(left <= right){
        int mid = left + (right - left) / 2;
        if(nums[mid] == target){
            first = mid;
            right = mid - 1;
        }else if(nums[mid] > target){
            right = mid - 1;
        }else{
            left = mid + 1;
        }
    }
    
    //确定first之后以first为起点向右遍历寻找最后一个索引last
    if(first != -1){
        last = first; //以first为起点
        while(last + 1 < numsSize && nums[last + 1] == target){
            last++; //不越界且target重复出现时last一直增加,直到最后一次出现
        }
    }
    res[0] = first;
    res[1] = last;
    return res;
}

注意:

  • last + 1 < numsSize 的判断要在 nums[last + 1] == target 的前面,否则对于边界元素会出现数组越界问题。
  • 一般实际应用中我们使用了malloc进行动态内存分配之后,要在使用完毕的时候进行free释放,题中只是为了刷题所以没释放,勿学。

你可能感兴趣的:(leetcode数组篇,leetcode,算法,职场和发展)