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

题目

给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。
你的算法时间复杂度必须是 O(log n) 级别。
如果数组中不存在目标值,返回 [-1, -1]。

算法分析

  • 时间复杂度必须是 O(log n) 级别,表示要用二分法。
  • 由于是升序数组,因此算出 mid。
  • 对于 nums[mid] > target 这种情况,查找区域收缩为 [start, mid-1]。
  • 对于 nums[mid] < target 这种情况,查找区域收缩为 [mid+1, start]。
  • 对于 nums[mid] = target 这种情况,查找区域收缩为 [start, mid-1]。
public static int[] Method(int[] nums, int target)
{
    Array.Sort(nums);

    var left = SearchLeftRange(nums, target);

    int right = -1;
    if (left != -1)
        right = SearchRightRange(nums, target);

    return new int[] { left, right };
}

private static int SearchLeftRange(int[] nums, int target)
{
    int left = 0;
    int right = nums.Length - 1;

    while (left <= right)
    {
        int mid = left + (right - left) / 2; // 防止溢出、
        if (nums[mid] == target)
        {
            right = mid - 1;
        }
        else if (nums[mid] > target)
        {
            right = mid - 1;
        }
        else // nums[mid] < target
        {
            left = mid + 1;
        }
    }

    if (left != nums.Length && nums[left] == target)
    {
        return left;
    }

    return -1;
}

private static int SearchRightRange(int[] nums, int target)
{
    int left = 0;
    int right = nums.Length - 1;

    while (left <= right)
    {
        int mid = left + (right - left) / 2;
        if (nums[mid] == target)
        {
            left = mid + 1;
        }
        else if (nums[mid] < target)
        {
            left = mid + 1;
        }
        else // nums[mid] > target
        {
            right = mid - 1;
        }
    }

    return right;
}

注意:先搜索的边界函数(SearchLeftRange),如果 target 很大且不存在,需要判断 left 越界情况。同理,如果 target 很小且不存在,需要判断 right 越界情况,但 SearchLeftRange 已经可以知道 target 是否存在了。

你可能感兴趣的:(Leecode[34] 在排序数组中查找元素的第一个和最后一个位置)