数组二分法
一、题源:
704. 二分查找
问题描述
给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。
二、 思路:
1、暴力解法
最容易想到的方法就是直接对数组进行遍历,对比数组元素与target。
时间复杂度:
O
(
n
)
O(n )
O(n)
空间复杂度:
O
(
1
)
O(1)
O(1)
注:暴力法虽然思路简单,容易想到,但是对于这个问题还有时间复杂度更低的方法
2、二分法
对于有序不重复的数组,可以针对题目要求考虑是否可以用二分法实现。
对于二分法的实现有不同的写法,但是很容易写乱,循环里面到底是left <= right还是left < right,还有迭代时mid和left还有right的关系,这些都是比较容易出错的点,对于这个问题大家可以详细参考二分查找
总结来看
- 对于左闭右闭[left, right],循环时left <= right,因为left == right有意义
- 对于左闭右开[left, right),循环时left < right,因为left == right没有意义
- 对于迭代时保持循环不变量原则,保证迭代后的区间和之前设置的区间开闭一致。
参考代码 (左闭右闭[left, right])
int search(int* nums, int numsSize, int target) {
int low = 0,high = numsSize - 1, mid;
while(low <= high) {
mid = (low + high) / 2;
if(nums[mid] == target) return mid;
else if(nums[mid] > target) {
high = mid - 1;//[low, mid - 1]
}
else {
low = mid + 1;//[mid + 1, high]
}
}
return -1;
}
参考代码 (左闭右开[left, right))
int search(int* nums, int numsSize, int target) {
int low = 0,high = numsSize, mid;
while(low < high) {
mid = (low + high) >> 1;
if(nums[mid] == target) return mid;
else if(nums[mid] > target) {
high = mid;//[low, mid)
}
else {
low = mid + 1;//[mid + 1, high)
}
}
return -1;
}
时间复杂度:
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)
空间复杂度:
O
(
1
)
O(1)
O(1)
三、相关题目及C语言实现
35. 搜索插入位置
问题描述:
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
请必须使用时间复杂度为 O ( l o g n ) O(log n) O(logn) 的算法。
实现:
int searchInsert(int* nums, int numsSize, int target){
int low = 0, high = numsSize - 1, mid;
while(low <= high){
mid = (low + high) >> 1;
if(nums[mid] == target) return mid;
else if(nums[mid] < target) low = mid + 1;
else high = mid -1;
}
return low;
}
34. 在排序数组中查找元素的第一个和最后一个位置
问题描述:
给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。
如果数组中不存在目标值 target,返回 [-1, -1]。
实现:
int* searchRange(int* nums, int numsSize, int target, int* returnSize){
int low = 0, high = numsSize - 1, mid;
int* result = (int*)malloc(sizeof(int)*2);
*returnSize = 2;
while(low <= high){
mid = (low + high) >> 1;
if(nums[mid] == target)
{
int i = mid;
while(i > 0 && nums[i-1] ==target) i--;
result[0] = i;
i = mid;
while(i < numsSize-1 && nums[i+1] == target) i++;
result[1] = i;
return result;
}else if(nums[mid] < target) low = mid + 1;
else high = mid - 1;
}
result[0] = -1;
result[1] = -1;
return result;
}