二分法(C#)
二分法思路:
将数组分成两部分,根据条件判断需要哪部分,舍弃掉不符条件的部分。继续在需要的部分里继续二分,直到得到结果。
适用:
二分法适合应用在有序数组中,对于特殊情况的无序数组也可以使用二分法
应用例子
1、在一个有序数组array[N]中,判断某个数(find)是否存在;
思路:
利用二分法,找到中间值mid,mid与find比较
若mid=find 返回
若mid<find 在array[start]~array[mid-1]之间在二分,继续判断二分
若mid>find 在array[mid-1]~array[end]之间二分,继续判断二分
注:mid,中间位置。start,数组头。end,数组尾
代码实现
public bool FindNumber(int[] arr,int find)
{
int start = 0;//记录每次二分的数组头部序号
int end = arr.Length - 1;//记录每次二分的数组尾部序号
int mid = (arr.Length - 1) / 2;//记录每次二分的数组中间序号
while (start <= end)
{
if (find == arr[mid])
return true;
else if (find < arr[mid])
end = mid-1;
else
start = mid+1;
mid = (start + end) / 2;
}
return false;
}
2、在一个有序数组array[N]中,找到>=某个数(find)最左侧的位置
例:数组arr[1,1,2,2,2,4,4,4,5,5,5,6,6,7],找到>=4最左侧位置
输出:arr[5]
思路
(1) 利用二分法,找到中间值mid,mid与find比较(一定要二分到结束)
(2)若mid>=find 记录此时位置t,在array[start]~array[mid]之间二分(每次mid符合>=find,要将mid的序号与t比较,若是小于t,更新t为mid的序号)
(3)若mid<find 在array[mid]~array[end]之间二分。
代码实现
public int Findleft(int[] arr, int find)
{
int start = 0;
int end = arr.Length - 1;
int mid = (arr.Length - 1) / 2;
int t = arr.Length;//记录每一步中找到的位置
while (end-start>1)
{
if (arr[mid] >= find)
{
if(t>mid)
t = mid;
end = mid;
}
else if (arr[mid] < find)
{
start = mid;
}
mid = (start + end) / 2;
}
return t;
}
3、在一个无序数组array[N],限定数组array相邻数不相等,局部最小值问题
局部最小值定义:
array[0]<array[1],array[0]为局部最小值
array[N-1]<array[N-2],array[N-1]为局部最小值
array[i]<array[i-1]且array[i]<array[i+1],array[i]为局部最小值
思路
(1)先判断array[0]和array[N-1]处是不是局部最小值,若是则返回,若都不是则此时数组中元素大小状态如下图。
所以根据上图可知数组内一定存在局部最小值。
(2)进行一次二分,找到中间值mid,让mid与左右比较。
若array[mid]<array[mid-1]&&array[mid]<array[mid+1],则array[mid]为局部最小值,返回即可。
若array[mid]>array[mid-1],下图显示了数组当时的大小趋势,此时array[start]到array[mid]之间一定有局部最小值,在array[start]——array[mid]之间在二分。下图是大小状态。
同理,若array[mid]>array[mid+1],则array[mid]到array[end]之间一定有局部最小值,在array[mid]——array[end]之间二分,继续二分。
代码实现
public int FindMin(int[] arr)
{
int start = 0;
int end = arr.Length - 1;
int mid = (arr.Length - 1) / 2;
if (arr[0] < arr[1])
return 0;
else if (arr[arr.Length - 1] < arr[arr.Length - 2])
return arr.Length - 1;
else
{
while (start < end&&mid!=0&&mid!=arr.Length-1)
{
if (arr[mid] < arr[mid - 1] && arr[mid] < arr[mid + 1])
return mid;
else if (arr[mid] > arr[mid - 1])//当中间的值及大于左边,又大于右边(左右两侧都有局部最小值的时候,优先取前面的局部最小值)
end = mid;
else if (arr[mid] > arr[mid + 1])
start = mid;
mid = (end + start) / 2;
}
}
return -1;
}
如有问题,欢迎留言ヽ(✿゚▽゚)ノ