题目
给定一个按照升序排列的整数数组 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 是否存在了。