编程之美之二分查找总结

二分查找原理很简单,但是边界条件容易出错,出现死循环等,要想彻底分清楚,应该要理解透彻,大家可以用先思考,然后用例子来验证,下面是我的思路,如果有错误,请指正。我们先看变形一:如果有很多待查找的数字,找出最大的,所以最大的一定是在最右边,为了能够把左右两个数进行对比,循环结束的时候,左右指针对应的数要相隔1,所以循环结束的条件left < right -1;要想保留最大下标,当data[mid] == value时,不能结束,因为data[mid+1]也可能等于value,所以要继续遍历,这时让left = mid,不能让right=mid,因为mid右边可能还有等于value的值,所以小于和等于要合并。变形二类似。再看变形三:为了找data[i]<value的最大i,当data[i]==value时也不能结束,此时,由于i肯定是在等于value的那个下标的左边,所以当data[i]==value时,要把right = mid继续遍历,即把大于和等于合并,而此时和变形一不同的时,要找的是小于,而不是等于,所以当data[i]>=value时,结果肯定在i的左边,不可能包括i,所以right = mid -1而不是mid,变形四类似。

标准的二分查找一:

int biSearch(vector<int>& data,int value)
{
	int left = 0,right = data.size()-1;//注意1
	while(left <= right)//注意2
	{
		int mid = left + ((right - left) >> 1);//注意3
		if(data[mid] < value)left = mid + 1;
		else if(data[mid] > value)right = mid - 1;//注意4
		else return mid;
	}
	return -1;
}

标准的二分查找二(不常用):

int biSearch(vector<int>& data,int value)
{
	int left = 0,right = data.size();//注意1
	while(left < right)//注意2
	{
		int mid = left + ((right - left) >> 1);
		if(data[mid] < value)left = mid + 1;
		else if(data[mid] > value)right = mid;//注意3
		else return mid;
	}
	return -1;
}

变形一:如果有多个满足条件,返回序号最大的

int biSearch(vector<int>& data,int value)
{
	int left = 0,right = data.size()-1;//注意1
	while(left < right - 1)
	{
		int mid = left + ((right - left) >> 1);
		if(data[mid] <= value)left = mid;//注意2
		else right = mid;//注意3
	}
	if(data[right] == value)return right;
	if(data[left] == value)return left;
	return -1;
}

变形二:如果有多个满足条件,返回序号最小的

int biSearch(vector<int>& data,int value)
{
	int left = 0,right = data.size()-1;//注意1
	while(left < right - 1)
	{
		int mid = left + ((right - left) >> 1);
		if(data[mid] >= value)right = mid;//注意2
		else left = mid;//注意3
	}
	if(data[left] == value)return left;
	if(data[right] == value)return right;
	return -1;
}

变形三:求最大的i,使得data[i] < value

int biSearch(vector<int>& data,int value)
{
	int left = 0,right = data.size()-1;//注意1
	while(left < right - 1)
	{
		int mid = left + ((right - left) >> 1);
		if(data[mid] < value)left = mid;//注意2
		else right = mid-1;//注意3
	}
	if(data[right] < value)return right;
	if(data[left] < value)return left;
	return -1;
}

变形四:求最小的i,使得data[i] > value

int biSearch(vector<int>& data,int value)
{
	int left = 0,right = data.size()-1;//注意1
	while(left < right - 1)
	{
		int mid = left + ((right - left) >> 1);
		if(data[mid] > value)right = mid;//注意2
		else left = mid + 1;//注意3
	}
	if(data[left] > value)return left;
	if(data[right] > value)return right;
	return -1;
}

leetcode 之 

Search Insert Position

 

Given a sorted array and a target value, return the index if the target is found. If not, return the index where it would be if it were inserted in order.

You may assume no duplicates in the array.

Here are few examples.
[1,3,5,6], 5 → 2
[1,3,5,6], 2 → 1
[1,3,5,6], 7 → 4
[1,3,5,6], 0 → 0

class Solution {
public:
    int searchInsert(int A[], int n, int target) {
    	int left = 0,right = n -1;
    	while(left < right-1)
    	{
    		int mid =left + ((right-left)>>1);
    		if(A[mid] > target)right = mid -1;
    		else left = mid;
    	}
    	if(A[right] == target)return right;
    	if(A[right] < target)return right+1;
    	if(A[left] >= target)return left;
    	return left+1;
    }
};

Search for a Range

Given a sorted array of integers, find the starting and ending position of a given target value.

Your algorithm’s runtime complexity must be in the order of O(log n).

If the target is not found in the array, return [-1, -1].

For example,
Given [5, 7, 7, 8, 8, 10] and target value 8,
return [3, 4].

class Solution {
public:
    vector<int> searchRange(int A[], int n, int target) {
    	int start = 0,end = n-1;
    	vector<int> res(2);
    	while(start < end - 1)//查找开始位置
    	{
    		int mid = start + ((end - start)>>1);
    		if(A[mid] >= target)end = mid;
    		else start = mid + 1;
    	}
    	if(A[start] == target)
    	{
    		res[0] = start;
    	}
    	else if(A[end] == target)
    	{
    		res[0] = end;
    		start = end;
    	}
    	else 
    	{
    		res[0] = res[1] = -1;
    		return res;
    	}
    	end = n-1;
    	while(start < end - 1)//查找结束位置
    	{
    		int mid = start + ((end-start)>>1);
    		if(A[mid] <= target)start = mid;
    		else end = mid - 1;
    	}
    	if(A[end] == target)res[1] = end;
    	else if(A[start]== target)res[1]=start;
    	return res;
    }
};

leetcde之Submission Details

Write an efficient algorithm that searches for a value in an m x n matrix. This matrix has the following properties:

  • Integers in each row are sorted from left to right.
  • The first integer of each row is greater than the last integer of the previous row.

For example,

Consider the following matrix:

[
  [1,   3,  5,  7],
  [10, 11, 16, 20],
  [23, 30, 34, 50]
]

Given target = 3, return true.

思路:从右上角开始,先进行二分查找找到哪一行,该二分查找属于找到第一个大于目标的类型,然后在该行进行普通的二分查找。

class Solution {
public:
    bool searchMatrix(vector<vector<int> > &matrix, int target) {
    	int rows = matrix.size();
    	if(rows <= 0)return false;
    	int cols = matrix[0].size();
    	if(cols <= 0)return false;
    
    	int up = 0,bottom = rows - 1;
    	while(up < bottom - 1)//二分查找target在哪一行
    	{
    		int mid = up + ((bottom - up)>>1);
    		if(matrix[mid][cols-1] > target)bottom = mid;
    		else if(matrix[mid][cols-1] < target)up = mid + 1;
    		else return true;
    	}
    	if(matrix[up][cols-1] < target)up = bottom;
    	int left = 0,right = cols - 1;
    	while(left <= right)//二分查找在哪一列
    	{
    		int mid = left + ((right-left)>>1);
    		if(matrix[up][mid] > target)right = mid - 1;
    		else if(matrix[up][mid] < target)left = mid + 1;
    		else return true;
    	}
    	return false;
    }
};

关于二分查找之旋转数组,请看这里

    原文作者:fangjian1204
    原文地址: https://blog.csdn.net/fangjian1204/article/details/38705183
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞