算法学习(3):二分
二分法
二分法的常规用法:在一个有序数组中查找某个数是否存在
在数组arr中查找num,如果找到则返回下标,没找到返回-1。
int binarySearch(vector<int> arr, int num)
{
int left = 0;
int right = arr.size() - 1;
int mid;
while (left <= right)
{
mid = left + (right - left) / 2;
if (num < arr[mid])
right = mid - 1;
else if (num > arr[mid])
left = mid + 1;
else
return mid;
}
return -1;
}
在一个有序数组中,找到大于等于某个数最左侧的位置
思路:首先用数组最中间的数与目标数字比较,如果大于等于目标数字,则用index记录下来,此时最中间的数左边还有可能有符合条件的数,对左边再次二分查找;如果第一次比较,数组最中间的数小于目标数字,则代表最中间的数右侧可能有符合条件的数,对右边二分查找;每次查找如果有符合条件的数,则用index记录下来,向左二分,不符合条件则向右,不记录,循环结束时,index记录的数就是解。
//找到则返回下标,没找到则返回-1
int findPosition(vector<int> arr, int num)
{
int index = -1;
int left = 0;
int right = arr.size() - 1;
int mid;
while (left <= right)
{
mid = left + (right - left) / 2;
if (arr[mid] >= num)
{
index = mid;
right = mid - 1;
}
else if (arr[mid] < num)
{
left = mid + 1;
}
}
return index;
}
局部最小值问题(二分思想的扩展,无序也可以二分)
给定一个数组,规定相邻两个数一定不相等,求一个局部最小值。
局部最小值定义:下标为0的数如果小于下标为1的数,则下标为0的数为局部最小值;下标为N-1的数如果小于下标为N-2的数,则下标为N-1的数为局部最小值;处于数组中间的数如果它同时小于自己两边的数,则为局部最小值。
解题思路:首先判断数组第一个和最后一个数是否为局部最小值,如果是则返回,如果不是,则代表数组中间一定存在一个局部最小值
因为此时数组的数字大小趋势为上图所示,中间不管怎么连接,都会出现一个起伏(因为题干中规定相邻数字不相同),则必定会有“谷底”,“谷底”就是局部最小值。二分,比较最中间的数与其相邻左右两边的数的大小,如果两边的数都比它大,则找到局部最小值,返回;如果左边或者右边的数大,则哪个小向哪边二分,同时重复前面的步骤,直到找出局部最小值。
int findLocalMin(vector<int> arr)
{
int length = arr.size();
int left = 0;
int right = length - 1;
int mid;
if (arr.size() < 2)
return -1;
else
if (arr[0] < arr[1])
return 1;
else if (arr[length - 1] < arr[length - 2])
return length - 1;
else
{
while (left <= right)
{
mid = left + (right - left) / 2;
if (arr[mid] < arr[mid + 1] && arr[mid] < arr[mid - 1])
return mid;
else if (arr[mid] > arr[mid - 1])
right = mid - 1;
else if (arr[mid] > arr[mid + 1])
left = mid + 1;
}
}
//return mid;
}
浙公网安备 33010602011771号