LeetCode——34. 在排序数组中查找元素的第一个和最后一个位置(二分)

34. 在排序数组中查找元素的第一个和最后一个位置(二分)

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

题目

著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
给定一个按照升序排列的整数数组 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]

代码

//从两侧分别二分寻找目标在数组中第一个和最后一个位置
class Solution {
    public int[] searchRange(int[] nums, int target) {
        int len = nums.length;
        int left = 0;
        int right = len - 1;
        if(len == 0){
            return new int[]{-1, -1};
        }
        int first = findFirstLOC(nums, target);//先从前往后找到target第一个位置,如果不存在就可以返回-1了
        if(first == -1){
            return new int[]{-1, -1};
        }
        int last = findLastLOC(nums, target);//第一个下标存在才会找最后一个下标,所以最不济只有一个等于target
        return new int[]{first, last};
    //    return new int[]{last, first};
    }
    public int findFirstLOC(int[] nums, int target) {//从前往后找到target第一个位置
        int len = nums.length;
        int left = 0;
        int right = len - 1;
        while(left < right){
            int mid = left + (right - left) / 2;
            if(nums[mid] < target){//小于target一定不是解
            //下一个搜索区间为[mid + 1, right]
                left = mid + 1;
            }
            else{
                right = mid;
            }
        }
        if(nums[left] == target){
            return left;
        }
        else{
            return -1;
        }
    }
    public int findLastLOC(int[] nums, int target) {//从后往前找到target最后一个位置
        int len = nums.length;
        int left = 0;
        int right = len - 1;
        while(left < right){
            int mid = left + (right - left + 1) / 2;//left = mid时,一定注意上取整
            if(nums[mid] > target){//大于target一定不是解
            //下一个搜索区间为[left, mid -1]
                right = mid - 1;
            }
            else{//小于target时
                left = mid;
            }
        }
        return left;
    }
}

思想

题目要求算法时间复杂度必须是 O(log n) 级别,又数组递增有序,立刻想到二分搜索,根据二分查找的思想。先从左侧搜索target找寻第一个下标,如果没找到返回[-1, -1];再从右侧搜索target的最后一个下标,返回[leftLOC, rightLOC]即可。
整体思想比较简明,但是代码细节很繁琐,至今还有些不明朗。

关于二分查找的问题

• 掌握二分查找的两种思路重点:
• 思路 1:在循环体内部查找元素:while (left <= right);
• 思路 2:在循环体内部排除元素:while (left < right)。
• 全部使用左闭右闭区间,不建议使用左闭右开区间,反而使得问题变得复杂;
这里如何区分使用场景呢?
int mid = left + (right - left) / 2;//下取整
int mid = left + (right - left + 1) / 2;//left = mid时,一定注意上取整
两者如何区分?

猜你喜欢

转载自blog.csdn.net/qq_34767784/article/details/107015149