GuilinDev

Lc0034

05 August 2008

34 Find First and Last Position of Element in Sorted Array (Search for a Range)

原题概述

Given an array of integers ‘nums’ sorted in ascending order, find the starting and ending position of a given ‘target’ value.

Your algorithm’s runtime complexity must be in the order of O(log n).

If the target is not found in the array, return [-1, -1].

Example 1:

1
2
Input: nums = [5,7,7,8,8,10], target = 8
Output: [3,4]

Example 2:

1
2
Input: nums = [5,7,7,8,8,10], target = 6
Output: [-1,-1]

题意和分析

已经升序排好的数组里面可能有重复的数字,找到给定的target值的起始下标和结束下标。没有就返回[-1, -1],如果只有一个则返回两个同样的下标。要求复杂度为O(logn)。

1)暴力法直接遍历:直接用for循环从左到右遍历,时间复杂度为O(n),所以会超时。先找记录第一次nums[i] = target,result[0] = i,之后继续遍历,直至nums[i] != target,result[1] = i。

2)二分查找法:做两次二分查找分别找左边界和右边界,分别特殊处理当nums[mid] == target的情况;对于查找左边界的二分查找,当nums[mid]== target的时候,移动右下标right为mid - 1;对于查找右边界的二分查找,当nums[mid] == target的时候,移动做下标left为mid + 1;注意在两个二分查找过程中,每次nums[mid] == target时都需要更新result,

两个二分查找,Time:2 × O(logn) = O(logn),Space:O(1)。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
public int[] searchRange(int[] nums, int target) {
        int[] result = {-1, -1};
        if (nums == null || nums.length == 0) {
            return result;
        }
        int left = 0;
        int right = nums.length - 1;
        while (left + 1 < right) {
            int mid = left + (right - left) / 2;
             if (nums[mid] >= target) { // 找左边界,找到了一个target,还需要继续往左边找
                right = mid;
            } else {
                left = mid;
            }
        }
        // 这个模板left和right都可能是target,先判断右边界再判断左边界,以免可能正确的更左的左边界left被覆盖
        if (nums[right] == target) {
            result[0] = right;
        }
        if (nums[left] == target) {
            result[0] = left;
        } 
        
        
        left = 0;
        right = nums.length - 1;
        
        while (left + 1 < right) {
            int mid = left + (right - left) / 2;
             if (nums[mid] <= target) { // 找右边界,找到了一个target,还需要继续往右边找
                left = mid;
            } else {
                right = mid;
            }
        }
        
        // 这个模板left和right都可能是target,先判断左边界再判断右边界,以免更右的右边界right被覆盖
        if (nums[left] == target) {
            result[1] = left;
        }
        if (nums[right] == target) {
            result[1] = right;
        }
        
        return result;
    }