关于Binary Search的写法总结

1. 使用闭区间,初始化 start = 0, end = n-1。

2. 循环条件  while (start <= end)

3. 中间元素的取法: int mid = low + ((high - low) / 2);

一段典型的code:

1:     public static int binarySearch(int[] a, int key) {
2:         int low = 0;
3:         int high = a.length - 1;
4:
5:         while (low <= high) {
6:             int mid = low + (high-low) / 2;
7:             int midVal = a[mid];
8:
9:             if (midVal < key)
10:                 low = mid + 1
11:             else if (midVal > key)
12:                 high = mid - 1;
13:             else
14:                 return mid; // key found
15:         }
16:         return -1;  // key not found.
17:     }


Leetcode 相关题目: Search for a Range, Search in Rotated Sorted Array, Search in Rotated Sorted Array II

Leetcode: Search in Rotated Sorted Array 代码:

4. 边界条件。当end-start = 1时,注意mid = start,此时如果A[start]不符合条件,应该转向start = mid+1,搜索第二个元素,而如果end = mid-1,则直接退出循环而发生错误。

直观来看,如果int mid = low + ((high - low) / 2); 则应将 if(A[start] < A[mid])和 if(A[start] == A[mid])合并为一种情况来处理(都应搜索后半部分)。

如果int mid = low + ((high - low +1) / 2); 应将if(A[mid] < A[end])和 if(A[end] == A[mid]) 合并为一种情况(都应搜索前半部分)。


class Solution {
public:
    int search(int A[], int n, int target) 
    {
        if(n == 0) return -1;
        //if(n == 1) return A[0] == target?0:-1;
        
        int start = 0, end = n-1;
        
        while(start <= end)
        {
            int mid = start + (end - start)/2;
            if(A[mid] == target) return mid;
            if(A[start] <= A[mid])
            {
                if(A[start] <= target && target < A[mid])
                    end = mid-1;
                else
                    start = mid+1;
            }
            else
            {
                if(A[mid] < target && target <= A[end])
                    start = mid+1;
                else
                    end = mid-1;
            }
        }
        return -1;
    }
};

Leetcode: Search in Rotated Sorted Array II 代码:

class Solution {
public:
    bool search(int A[], int n, int target) {
        if(n == 0) return false;
        
        int start = 0, end = n-1;
        while(start <= end)
        {
            int mid = start + (end - start)/2;
            if(A[mid] == target) return true;
            
            if(A[start] < A[mid])
            {
                if(A[start] <= target && target < A[mid])
                    end = mid-1;
                else
                    start = mid+1;
            }
            else if(A[start] > A[mid])
            {
                if(A[mid] < target && target <= A[end])
                    start = mid+1;
                else
                    end = mid-1;
            }
            if(A[start] == A[mid])
                start++;
            if(A[mid] == A[end])
                end--;
        }
        return false;
    }
};

题目: Find the minimum element in a sorted and rotated array

http://www.geeksforgeeks.org/find-minimum-element-in-a-sorted-and-rotated-array/

int findMin(int arr[], int n)
{
	int low = 0;
	int high = n-1;
	if(n == 1) return arr[0];

	while (low <= high)
	{
	    // Find mid
	    int mid = low + (high - low)/2;
	    if(mid-1 >= 0 && arr[mid-1] > arr[mid])
	    	return arr[mid];
	    if(mid+1 < n && arr[mid] > arr[mid+1])
	    	return arr[mid+1];

	    if(arr[low] <= arr[mid])
	    	low = mid + 1;
	    else
	    	low = mid - 1;
	}
	return arr[0];
}

// Driver program to test above functions
int main()
{
    int arr1[] =  {5, 6, 1, 2, 3, 4};
    int n1 = sizeof(arr1)/sizeof(arr1[0]);
    printf("The minimum element is %d\n", findMin(arr1, n1));

    int arr2[] =  {1, 2, 3, 4};
    int n2 = sizeof(arr2)/sizeof(arr2[0]);
    printf("The minimum element is %d\n", findMin(arr2, n2));

    int arr3[] =  {1};
    int n3 = sizeof(arr3)/sizeof(arr3[0]);
    printf("The minimum element is %d\n", findMin(arr3, n3));

    int arr4[] =  {1, 2};
    int n4 = sizeof(arr4)/sizeof(arr4[0]);
    printf("The minimum element is %d\n", findMin(arr4, n4));

    int arr5[] =  {2, 1};
    int n5 = sizeof(arr5)/sizeof(arr5[0]);
    printf("The minimum element is %d\n", findMin(arr5, n5));

    int arr6[] =  {5, 6, 7, 1, 2, 3, 4};
    int n6 = sizeof(arr6)/sizeof(arr6[0]);
    printf("The minimum element is %d\n", findMin(arr6, n6));

    int arr7[] =  {1, 2, 3, 4, 5, 6, 7};
    int n7 = sizeof(arr7)/sizeof(arr7[0]);
    printf("The minimum element is %d\n", findMin(arr7, n7));

    int arr8[] =  {2, 3, 4, 5, 6, 7, 8, 1};
    int n8 = sizeof(arr8)/sizeof(arr8[0]);
    printf("The minimum element is %d\n", findMin(arr8, n8));

    int arr9[] =  {3, 4, 5, 1, 2};
    int n9 = sizeof(arr9)/sizeof(arr9[0]);
    printf("The minimum element is %d\n", findMin(arr9, n9));

    return 0;
}


有重复元素的情况:

class Solution {
public:
    int findMin(vector<int> &arr) {
        const int n = arr.size();
    <span style="white-space:pre">	</span>int low = 0;
    <span style="white-space:pre">	</span>int high = n-1;
    <span style="white-space:pre">	</span>if(n == 1) return arr[0];
        
    <span style="white-space:pre">	</span>while (low <= high)
    <span style="white-space:pre">	</span>{
    <span style="white-space:pre">	</span>    // Find mid
    <span style="white-space:pre">	</span>    int mid = low + (high - low)/2;
    <span style="white-space:pre">	</span>    if(mid-1 >= 0 && arr[mid-1] > arr[mid])
    <span style="white-space:pre">	</span>    <span style="white-space:pre">	</span>return arr[mid];
    <span style="white-space:pre">	</span>    if(mid+1 < n && arr[mid] > arr[mid+1])
    <span style="white-space:pre">	</span>    <span style="white-space:pre">	</span>return arr[mid+1];
    
            if(arr[mid] < arr[high])
                high = mid-1;
            else if(arr[mid] > arr[high])
                low = mid+1;
            else
                high--;
    <span style="white-space:pre">	</span>}
    <span style="white-space:pre">	</span>return arr[0];
    }
};

总结: 这两个题目中,如果元素有重复,只能利用以下代码段,逐一跳过重复元素。运行时间介于O(logN)和O(n)之间。

	    if(arr[low] == arr[mid])
	    	low++;
	    else if(arr[mid] == arr[high])
	    	high--;


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值