34. 在排序数组中查找元素的第一个和最后一个位置[中等]

268 阅读1分钟

问题

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

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

思路

基本思路是用二分查找。当找第一个时,如果nums[mid]恰好为target,需要判断mid的左边的数字是否是target,如果是可以往左找;否则直接返回。找最后一个时,同理可得。

代码

class Solution {
    public int[] searchRange(int[] nums, int target) {
        int low = findLowIndex(nums, target);
        int high = findHighIndex(nums, target);
        return new int[] {low, high};
    }
​
    private int findLowIndex(int[] nums, int target) {
        if (nums == null || nums.length == 0) {
            return -1;
        }
        int low = 0;
        int high = nums.length - 1;
        
        while (low <= high) {
            int mid = (low + high) / 2;
            if (nums[mid] == target) {
                // mid-1后不要超过low
                if (mid - 1 >= low && nums[mid - 1] == target ) {
                    high = mid - 1;
                } else {
                    return mid;
                }
            }
            if (nums[mid] > target) {
                high = mid - 1;
            } 
            if (nums[mid] < target) {
                low = mid + 1;
            }
        }
        return -1;
    }
​
    private int findHighIndex(int[] nums, int target) {
        if (nums == null || nums.length == 0) {
            return -1;
        }
        int low = 0;
        int high = nums.length - 1;
        
        while (low <= high) {
            int mid = (low + high) / 2;
            if (nums[mid] == target) {
                if (mid + 1 <= high && nums[mid + 1] == target) {
                    low = mid + 1;
                } else {
                    return mid;
                }
            }
            if (nums[mid] > target) {
                high = mid - 1;
            } 
            if (nums[mid] < target) {
                low = mid + 1;
            }
        }
        return -1;
    }
}

代码二

public class Solution {
    public int[] searchRange(int[] nums, int target) {
        int[] result = {-1, -1};
        int start = 0; 
        int end = nums.length - 1;
        int mid = 0;
        while (start <= end) {
            mid = start + ((end - start) >>> 1);
            //target < nums[mid]肯定往左找
            //找下确界,即使相等也要往左找
            if (target <= nums[mid]) {
                end = mid - 1;
            } else {
                //target >= nums[mid]
                start = mid + 1;
            }
        }
        if (start < nums.length && nums[start] == target) {
            result[0] = start;
            end = nums.length - 1;
            while (start <= end) {
                mid = start + ((end - start) >>> 1);
                if (target < nums[mid]) {
                    end = mid - 1;
                } else {
                    start = mid + 1;
                }
            }
            result[1] = end;
            return result;
        }
       
        return result;
    }
}

官方

官方给的思路:相当于查找第一个大于等于target的下标,和第一个大于​target的下标-1。

如果查找第一个大于等于target的下标,只需要在原有二分法中,当大于等于就往左走​。

class Solution {
    public int[] searchRange(int[] nums, int target) {
        int left = binarySearch(nums, target, true);
        int right = binarySearch(nums, target, false) - 1;
        if (left <= right && nums[left] == target && nums[right] >= target) {
            return new int[] {left, right};
        }
        return new int[] {-1, -1};
    }
​
    // 第一个大于target或者第一个大于等于target的下标
    private int binarySearch(int[] nums, int target, boolean left) {
        int low = 0, high = nums.length - 1, res = nums.length;
        while (low <= high) {
            int mid = (low + high) / 2;
            if (nums[mid] > target || (left && nums[mid] >= target)) {
                high = mid - 1;
                res = mid;
            } else {
                low = mid + 1;
            }
        }
        return res;
    }
}

复杂度

时间复杂度:O(logn) 空间复杂度:O(1)

硬广告

欢迎关注公众号:double6