二分查找
二分查找模板题:704. 二分查找
二分查找前提:
- 有序数组
- 数组中无重复元素
左闭右闭:
class Solution {
public:
int search(vector<int>& nums, int target) {
int left = 0;
int right = nums.size() - 1;
while (left <= right) {
int mid = left + ((right - left) / 2);
if (nums[mid] > target) {
right = mid - 1;
} else if (nums[mid] < target) {
left = mid + 1;
} else return mid;
}
return -1;
}
};
左闭右开
class Solution {
public:
int search(vector<int>& nums, int target) {
int left = 0;
int right = nums.size();
while (left < right) {
int mid = left + ((right - left) / 2);
if (nums[mid] > target) {
right = mid;
} else if (nums[mid] < target) {
left = mid + 1;
} else return mid;
}
return -1;
}
};
时间复杂度:
O
(
l
o
g
n
)
O(logn)
O(logn)
空间复杂度:
O
(
1
)
O(1)
O(1)
二分查找拓展题:
【1】35.搜索插入位置
有两种情况考虑:
- 在数组中:二分查找
- 不在数组中:
- 所有数之前
- 在某两数之间
- 在所有数之后
而不在数组中即在二分查找的基础上改变退出循环后返回的值
二分查找退出循环时,左闭右闭left=right+1,左闭右开left=right
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
int left = 0, right = nums.size() - 1;
while (left <= right) {
int mid = (left + right) / 2;
if (nums[mid] > target) right = mid - 1;
else if (nums[mid] < target) left = mid + 1;
else return mid;
}
return right + 1;
}
};
时间复杂度:
O
(
l
o
g
n
)
O(logn)
O(logn)
空间复杂度:
O
(
1
)
O(1)
O(1)
【2】69. x 的平方根
class Solution {
public:
int mySqrt(int x) {
int left = 0; int right = x;
while (left <= right) {
int mid = (left + right) / 2;
if ((long long)mid * mid > x) right = mid - 1;
else if ((long long)mid * mid < x) left = mid + 1;
else return mid;
}
return right;
}
};
【3】367. 有效的完全平方数
class Solution {
public:
bool isPerfectSquare(int num) {
int left = 0;
int right = num;
while (left <= right) {
int mid = (left + right) / 2;
if ((long long)mid * mid > num) right = mid - 1;
else if ((long long)mid * mid < num) left = mid + 1;
else return true;
}
return false;
}
};
【4】34. 在排序数组中查找元素的第一个和最后一个位置
两次二分,定义新变量first、last
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
if (nums.size() == 0) return vector<int>{-1, -1};
int left = 0;
int right = nums.size() - 1;
int first = -1; int last = -1;
while (left <= right) {
int mid = (left + right) / 2;
if (nums[mid] > target) right = mid - 1;
else if (nums[mid] < target) left = mid + 1;
else {
first = mid;
right = mid - 1;
}
}
left = 0;
right = nums.size() - 1;
while (left <= right) {
int mid = (left + right + 1) / 2;
if (nums[mid] > target) right = mid - 1;
else if (nums[mid] < target) left = mid + 1;
else {
last = mid;
left = mid + 1;
}
}
return vector<int>{first, last};
}
};
【5】74. 搜索二维矩阵
二维转一维
class Solution {
public:
bool searchMatrix(vector<vector<int>>& matrix, int target) {
int m = matrix.size();
int n = matrix[0].size();
int left = 0;
int right = m * n - 1;
while (left <= right) {
int mid = (left + right) / 2;
int x = matrix[mid / n][mid % n];
if (x > target) right = mid - 1;
else if (x < target) left = mid + 1;
else return true;
}
return false;
}
};
【6】33. 搜索旋转排序数组
通过二分找到旋转点,在区间内部二分找到目标值
class Solution {
public:
int search(vector<int>& nums, int target) {
if (nums.size() == 0) return -1;
if (nums.size() == 1) {
if (nums[0] == target) return 0;
else return -1;
}
int left = 0, right = nums.size() - 1;
while (left <= right) {
int mid = (left + right) / 2;
if (nums[mid] == target) return mid;
if (nums[left] <= nums[mid]) {
if (nums[left] <= target && nums[mid] >= target) right = mid - 1;
else left = mid + 1;
} else {
if (nums[right] >= target && nums[mid] <= target) left = mid + 1;
else right = mid - 1;
}
}
return -1;
}
};
【7】153. 寻找旋转排序数组中的最小值
class Solution {
public:
int findMin(vector<int>& nums) {
int left = 0;
int right = nums.size() - 1;
while (left <= right) {
int mid = (left + right) / 2;
if (nums[mid] < nums[right]) right = mid;
else if (nums[mid] > nums[right]) left = mid + 1;
else return nums[mid];
}
return nums[left];
}
};