剑指offer53(二分的应用)

Posted ~千里之行,始于足下~

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了剑指offer53(二分的应用)相关的知识,希望对你有一定的参考价值。

接下来的这几个题目是以二分查找算法为基础,考察该算法的灵活应用
题目一:

解析:
在排序的数组中查找数字,我们首先相当的是二分查找.然后要统计target在数组中出现的次数,我们不妨找到第一个target的下标first,然后找到最后一个target的下标last,次数即为last-first+1.
代码:

//找目标值第一次出现
int GetFirstK(vector<int> data, int k, int l, int r) //k即为目标
    {
        int mid = 0;
        if (l > r)
            return -1;
        while (l <= r)
        {
            mid = l + ((r-l) >> 1);
            if (data[mid] == k) //若找到
            {
                //是否为数组第一个数字或数组前一个数字不等于k
                if (mid == 0 || (mid > 0 && data[mid-1] != k))
                {
                    return mid;//找到了第一个目标值
                }
                //数组中前一个数字等于k
                else if (mid > 0 && data[mid-1] == k)//
                {
                    r = mid - 1;
                }
            }
            else if (data[mid] > k)
            {
                r= mid - 1;
            }
            else
            {
                l = mid + 1;
            }
        }
        return -1; //未找到
    }
    //找目标值最后一次出现
    int GetLastK(vector<int> data, int k , int l, int r)
    {
        int mid = 0;
        if (l > r)
            return -1;
        while (l <= r)
        {
            mid = l + ((r-l) >> 1);
            if (data[mid] == k) //若找到
            {
                //数组中最后一个数字或数组中后一个数字不等于目标值
                if (mid == data.size()-1 || (mid < data.size()-1 && data[mid+1] != k))
                {
                    return mid; //找到了最后一个目标值
                }
                // 数组中后一个数字等于目标值
                else if (mid < data.size()-1 && data[mid+1] == k)
                {
                    l = mid + 1;
                }
            }
            else if (data[mid] > k)
            {
                r = mid - 1;
            }
            else
            {
                l = mid + 1;
            }
        }
        return -1; //未找到
    }
    int GetNumberOfK(vector<int> data ,int k) {
        if (0 == data.size())
            return 0;
        int len = data.size();
        int first = GetFirstK(data, k, 0, len-1);
        int last = GetLastK(data, k, 0, len-1);
        cout << first << endl;
        cout << last << endl;
        if (first > -1 && last > -1)
        {
            return (last - first + 1);
        }
        return 0;
    }

题目二:

分析:
方法1:
遍历数组,对数组求和为sum1; 利用求和公式对数字0~n-1求和为sum2, 缺失的数字即为sum2 - sum1.
方法2:: 在排序的数组中长度n-1,数字范围为0~n-1(n个).二分查找,碰到的第一个数字和它的下标不相等的即为缺失的数字;若相等, l = mid + 1
如: 长度为5, 数字范围为0~5
数字: 0 1 3 4 5
下标: 0 1 2 3 4
2即为缺失的数字.

代码:

//0~n-1(数字范围) 数组长度为n-1  有序 
	int GetMissingNum(const int * num, int len)
	{
		if (num)
		{
			int l = 0;
			int r = len - 1;
			while (l <= r)
			{
				int mid = l + ((r-l) >> 1);
				if (num[mid] != mid)//找到第一个数字与下标不等的
				{
				// 数组中前一个数字与下标相等
					if (mid == 0 || (mid > 0 && num[mid-1] == mid - 1))
					{
						return mid;
					}
					else
					{
						r = mid - 1;
					}
				}
				else //相等 向后缩小查找范围
				{
					l = mid + 1;
				}
			} 
		} 
		return -1;
	} 

题目三:

解析:
排序数组中寻找数值等于下标的,用二分法.若数值等于下标,找到;若数值>下标,r = mid-1;若数值<下标,l = mid + 1;
代码:

	// 数组中数值与下标相等的元素 无重复数字 
	int GetNumberSameAsIndex(const int * arr, int len)
	{
		if (arr)
		{
			int l = 0;
			int r = len - 1;
			while (l <= r)
			{
				int mid = l + ((r-l) >> 1);
				if (arr[mid] == mid) //找到
				{
					return mid;
				}
				else if (arr[mid] > mid)//数值>下标
				{
					r = mid - 1;
				}
				else     // 数值<下标
				{
					l = mid + 1;
				}
			}
		}
		return -1;
	 } 

以上是关于剑指offer53(二分的应用)的主要内容,如果未能解决你的问题,请参考以下文章

剑指offer二分53-I. 在排序数组中查找数字

剑指offer二分53-I. 在排序数组中查找数字

LeetCode 剑指Offer 53 - I 在排序数组中查找数字I[二分法] HERODING的LeetCode之路

剑指offer-面试题53_3-数组中数值和下标相等的元素-二分查找

剑指offer-面试题53_2-0~n-1中缺失的数字-二分查找

剑指 Offer 53