这是我参与8月更文挑战的第23天,活动详情查看:8月更文挑战
今天买了一个可转债,收益30%+。现在这个市场,可转债还是一个弯腰捡铜板的活,只要愿意每天申购,每年还是能中几个,而且一不小心,就像今天这样中的涨了30%,可不是捡了个鸡腿么。下次找机会做一个可转债的分享,适合作为A股新手项目。
晚上回来比较晚了,周一总是会忙一些,回来赶紧做题写文,今天继续做leetcode的第34题。
题目
给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。
如果数组中不存在目标值 target,返回 [-1, -1]。
进阶:
你可以设计并实现时间复杂度为 O(log n) 的算法解决此问题吗?
示例 1:
输入:nums = [5,7,7,8,8,10], target = 8
输出:[3,4]
示例 2:
输入:nums = [5,7,7,8,8,10], target = 6
输出:[-1,-1]
示例 3:
输入:nums = [], target = 0
输出:[-1,-1]
提示:
0 <= nums.length <= 105
-109 <= nums[i] <= 109
nums 是一个非递减数组
-109 <= target <= 109
思路
乍一看,这不就是一个二分查找吗?跟最基础的二分查找不同的,同样的值可能会出现多次,算是普通二分查找的一个变种吧。这点跟昨天的题目也是类似,昨天也是在最基础的二分查找的基础上,增加了一点小变化。本题就是要找到target的开始位置和结束位置,那我们怎么处理呢?
其实题意就是要求出最左边target的下标和最右边target的下标。普通的二分查找,我们找到target就结束了,方法就可以返回了,如果要求出最左边的target的下标,这时候还不能范围,因为左边可能还存在,我们就记录下当前的下标,然后再去左边继续用二分的方式去找,直到找到最左边,当然,求最右边target的方式也是一样的。
示意图如下,红色箭头为二分时的mid,第一次left = 0, right = 4, mid = 2, 发现num[mid] = target,此时虽然找到了,但是还不能直接返回,记录下下标2,right = mid - 1 = 1,继续用二分查找,直到找到最左边的2下标是1;查找最右边的2方法是一样的,只不过当num[mid] = target时,记录下当前下标后,要用left = mid
- 1 继续查找。
Java版本代码
class Solution {
public int[] searchRange(int[] nums, int target) {
int[] ans = new int[2];
ans[0] = searchRange(nums, target, true);
ans[1] = searchRange(nums, target, false);
return ans;
}
/**
* 在排序数组中查找元素的左边界和右边界,isLeft为true是左边界,isLeft为false是右边界
* @param nums
* @param target
* @param isLeft
* @return
*/
public static int searchRange(int[] nums, int target, boolean isLeft) {
int len = nums.length;
int ans = -1, left = 0, right = len - 1;
while (left <= right) {
int mid = (left + right) / 2;
if (nums[mid] == target) {
ans = mid;
if (isLeft) {
right = mid - 1;
} else {
left = mid + 1;
}
} else if (nums[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return ans;
}
}