LeetCode 34

 

        找排序数组特定元素的区间,意思是找开始下标和结束下标,但是题目给了要求时间复杂度低于 O(n),这就告诉我们不要使用遍历数组的方式来解题。我们查找单个元素的时候可以二分查找来完成,但是找区间的时候改用什么呢?比如:数组的排列顺序为:5 7 7 8 8 10,而 target = 8 ,我们该怎么找呢?答案还是二分查找,但是思路是这样的:我们先用二分查找找到 target 的大致位置,然后再利用该位置来查找开始下标和结束下标,意思是我们需要使用三次查找,(1)查找mid值,是nums[mid]==target ;

(2).以 left 和 mid去找开始下标;(3).以mid和right去找结束下标;说到这里应该比较明白了吧,但是我还是举个例子来说明吧:

 

上面的是大体上的思路,再注意到一些边界问题该题就可以解决了,代码如下:

class Solution {
public:
	vector<int> searchRange(vector<int>& nums, int target)
	{ //
		vector<int> ret;
		ret.clear();
		int len = nums.size();
		//非正常情况
		if (len == 0 || target < nums[0] || target > nums[len - 1])
		{
			ret.push_back(-1);
			ret.push_back(-1);
			return ret;
		}
		int left = 0;
		int right = len - 1;
		int mid = 0;
		//简单的二分查找时不能准确的找到开始和结束点的
		while (left <= right && nums[left]<=target && nums[right]>=target)
		{//有一边找到了target
			mid = left + (right - left) / 2;
			if (nums[mid] == target)
			{
				break;
			}
			if (nums[mid] < target)
			{
				left = mid + 1;
			}
			else
			{
				right = mid - 1;
			}
		}

        if(nums[left]>target || nums[right]<target)
        {
            //不合格,最后一起处理
        }
		else if (left == right)
		{
			if (nums[left] == target)
			{
				ret.push_back(left);
				ret.push_back(left);
				return ret;
			}
			else
			{
				//没找到,到最后一起处理
			}
		}
		else
		{ // left < right ,说明nums[mid] == target,那么分别向左找开始点和向右找结束点
			//左边
			int lbegin = left;
			int lend = mid;
			int lmid = 0;
			while (nums[lbegin] != target && nums[lbegin + 1] != target)
			{
				lmid = lbegin + (lend - lbegin) / 2;
				if (nums[lmid] == target)
				{//说明开始部位可能还在左边
					lend = lmid;
				}
				else
				{//nums[lmid]<target,此时说明在右边
					lbegin = lmid;
				}
			}
            //注意临界条件
			if (nums[lbegin] == target)
			{
				ret.push_back(lbegin);
			}
			else
			{
				ret.push_back(lbegin + 1);
			}

			//右边
			int rbegin = mid;
			int rend = right;
			int rmid = 0;
			while (nums[rend] != target && nums[rend - 1] != target)
			{
				rmid = rbegin + (rend - rbegin) / 2;
				if (nums[rmid] == target)
				{//说明结束部位还在右边
					rbegin = rmid;
				}
				else
				{
					rend = rmid;
				}
			}
			//注意临界条件
			if (nums[rend] == target)
			{
				ret.push_back(rend);
			}
			else
			{
				ret.push_back(rend - 1);
			}
			return ret;
		}
		
		//没找到
		ret.push_back(-1);
		ret.push_back(-1);
		return ret;
	}
};
结果如下:


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值