算法 C++二分搜索
二分搜索
时间复杂度
O(logN):最坏的情况下
O(1):恰好要找的数在最中间
寻找一个数
要点:数组是有序
bool exist(vector<int>& arr, int num)
{
if (arr == null || arr.size() == 0) {
return false;
}
int l = 0, r = arr.size() - 1;
int mid = 0;
while (l <= r) {
mid = (l + r) / 2;
if (arr[mid] > num) { // 中间值比要找的值还要大,说明arr[mid]后面的值都比num大,缩小右边界
r = m - 1;
}
else if (arr[mid] < num) { // 中间值比要找的值还要小,说明arr[mid]前面的值都比num大,扩大左边界
l = m + 1;
}
else {
return true;
}
}
return false;
}
寻找有序数组中找>=num的最左位置
int findLeft(vector<int>& arr, int num)
{
int l = 0, r = arr.size() - 1;
int mid = 0;
int ans = -1;
while (l <= r) {
mid = l + ((r - l) >> 1);
if (arr[mid] >= num) { // 中间值比要找的值还要大,说明arr[mid]后面的值都比num大,缩小右边界
ans = m;
r = m - 1;
}
else {
l = m + 1;
}
}
return ans;
}
有序数组中找<=num的最右位置
int findLeft(vector<int>& arr, int num)
{
int l = 0, r = arr.size() - 1;
int mid = 0;
int ans = -1;
while (l <= r) {
mid = l + ((r - l) >> 1);
if (arr[mid] <= num) { // 中间值比要找的值还要小,说明arr[mid]前面的值都比num大,扩大左边界
ans = m;
l = m + 1;
}
else {
r = m - 1;
}
}
return ans;
}
寻找峰值
要点:二分搜素并不只是用到有序数组
一个数组 [3,2,11,4,5,13,6,7]
峰值:中间的值大于两边的值,只看相邻的值
1 2 0 数组里面 2 就是峰值
寻找一个数组里面的第一个峰值:
1.设 -1 位置为一个特别小的值,设置 arr.size() + 1 的位置为一个很小的值
2.求 0 位置的值大于 1 位置的值
3.求 arr.size() - 1的值 大于 arr.size() - 2的值
4.求 1 ~ arr.size() - 2之间的峰值
当数组两边都是极小值的时候
最左边也就是 -1位置的值是 < 0位置的值,呈上升趋势。
最右边的值,arr.size() 位置的值,< arr.size() - 1位置的值,呈下降趋势。
一升一降,就会产生峰值。
int findPeakElement(vector<int>& arr) {
int n = arr.size();
if (arr.size() == 1) {
return 0;
}
if (arr[0] > arr[1]) {
return 0;
}
if (arr[n - 1] > arr[n - 2]) {
return n - 1;
}
int l = 1, r = n - 2, mid = 0,ans = -1;
while (l <= r) {
mid = l + ((r - l) >> 1);
if (arr[mid - 1] > arr[mid]) {
r = mid - 1;
}
else if (arr[mid] < arr[mid + 1]) {
l = mid + 1;
}
else {
ans = mid;
break;
}
}
return ans;
}