LeetCode.34在排序数组中查找元素的第一个和最后一个位置(Java+二分)

题目

给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。如果数组中不存在目标值 target,返回 [-1, -1]。
进阶: 你可以设计并实现时间复杂度为 O(log n) 的算法解决此问题吗?

示例:
输入:nums = [5,7,7,8,8,10], target = 6
输出:[-1,-1]

分析

思路:因为数组有序,且是查找某一个元素的位置,而且最好是实现O(log n),就要想到用二分查找来。我们只需要用两次二分查找,一次找前,一次找后。
这里是关于二分的文章,可以点进去看一下

1. 循环部分

找前(findTheFirstOne):

  • 如果nums[mid]>=target:说明已经出现过该目标值,而我们要找第一个出现的位置,那么我们应该去这个区间[left , mid-1]里面去找 ,那么令right =mid;
  • 如果nums[mid ]< target:说明前面没有出现过target,我们要去后面找,所以目标值出现的地方应该在这个[mid+1 ,right]区间,那么left =mid;

找后(findTheLastOne):

  • 如果nums[mid]>target:说明已经出现过该目标值,而我们要找最后一个出现的位置,那么我们应该去前面找[left, mid-1] ,那么令right =mid;
  • 如果nums[mid ]<= target:说明前面没有出现过target或者刚好等于target,我们就要去后面找最后出现的位置,所以目标值出现的地方应该在这个[mid+1 ,right]区间,那么left =mid;

2.判断

我们设置一个result数组,因为题目说了只返回第一个出现和最后一个出现的位置,也就是两个数,所以result数组的大小为2,我们初始化该数组{-1,-1},如果nums数组中存在target元素的第一个或最后一个的下标,我们就可以直接加进来,形成答案。如果数组长度为0或者nums数组中不存在target元素,都直接返回result。
判断一
——findTheFirstOne:

  1. 循环结束之后,会有left和right,若存在多个重复的target我们就要进行判断,如果nums[left]==target,则说明left指向的就是第一个出现的,否则的话,判断nums[right]==target,如果条件成立,则说明right指向的为第一个出现的位置。
  2. 如果两个if条件都不成立,说明没有该元素存在,result原来初始化的{-1,-1}也不会被改变的。
  3. 注意细节:应该先判断nums[left]==target是否成立,再判断nums[right]==target!!!因为找第一个

——findTheLastOne:

  1. 同理,但是这里要改为先判断nums[right]==target是否成立,再判断nums[left]==target!!——找最后一个

代码实现

	static int[] result = { -1, -1 };

	static public int[] searchRange2(int[] nums, int target) {
		if (nums.length == 0) {
			return result;
		}
		binarySearchToFindFirst(nums, target);
		binarySearchToFindLast(nums, target);
		return result;
	}

	static public void binarySearchToFindFirst(int[] nums, int target) {
		int left = 0, right = nums.length - 1;
		while (left + 1 < right) {
			int mid = left + (right - left) / 2;
			if (nums[mid] < target) {
				left = mid;
			} else {
				right = mid;
			}
		}
		if (nums[left] == target) {
			result[0] = left;
		} else if (nums[right] == target) {
			result[0] = right;
		}
	}

	static public void binarySearchToFindLast(int[] nums, int target) {
		int left = 0, right = nums.length - 1;
		while (left + 1 < right) {
			int mid = left + (right - left) / 2;
			if (nums[mid] <= target) {
				left = mid;
			} else {
				right = mid;
			}
		}
		if (nums[right] == target) {
			result[1] = right;
		} else if (nums[left] == target) {
			result[1] = left;
		}
	}

反思

之前看过二分查找的代码,但是没有完全搞明白,现在很清楚了。
end.

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值