算法图解——查找数组中元素的第一个和最后一个位置( Find First and Last Pos of Ele in Array)
1. 题目描述
Given an array of integers nums
sorted in ascending order, find the starting and ending position of a given target
value.If target
is not found in the array, return [-1, -1]
.Follow up: Could you write an algorithm with O(log n)
runtime complexity?
翻译:
给定按升序排序的整数nums数组,查找给定目标的起始和结束位置值。如果在数组中找不到目标,返回[-1,-1]。后续:是否可以编写运行时复杂度为O(logn)的算法?
2. 示例
示例1:
Input: nums = [5,7,7,8,8,10], target = 8
Output: [3,4]
示例2:
Input: nums = [5,7,7,8,8,10], target = 6
Output: [-1,-1]
示例3:
Input: nums = [], target = 0
Output: [-1,-1]
3. 要求
0 <= nums.length <= 105
-109 <= nums[i] <= 109
nums
is a non-decreasing array【非递减数组】.-109 <= target <= 109
4. 题目解析
看到这个题目中的要求,得知:数组为非递减,且要求复杂度为O(lgN),看到这个,我就想起了二分法查找,但是二分法查找是查找某一位数的,而不是查找多位。
所以,从这里出发其实有一个思路,就是:先用二分查找算法,找到一个等于target的数字的位置下标,然后再在该下标左右遍历,如有相同的数字,则肯定在左右两侧,因为数组是非递减的嘛。
但是,这样的话,复杂度就不是 lgN 了。
那么,该如何求解呢?不知道大家还记不记的C/C++中有一个函数叫 ceil() 和 floor() ,这两个分别是向上向下取整。
同样的思想,我们将target+0.5 和 target-0.5,然后查找这两个值在数组中的位置,找到后,中间夹着的区间就是 target 的所有下标位置。
所以,这题的关键就是实现二分查找算法,哈哈哈,如果hr直接考你二分算法,是不是好low,但是这样一包装就高大上了有木有?
5. 代码如下
class Solution { public int[] searchRange(int[] nums, int target) { if(nums==null || nums.length<=0){ return new int[]{-1,-1}; } Arrays.sort(nums); int left = binarySearch(nums,target - 0.5f); int right = binarySearch(nums,target + 0.5f); if(left == right){ return new int[]{-1,-1}; }else{ return new int[]{left,right-1}; } } public int binarySearch(int[] nums, float target){ int left = 0; int right = nums.length-1; while(left<right){ //int mid = left+(right-left)>>1;//这里需要注意,本来是想用移位操作符,但是要考虑计算优先级;
int mid = left+((right-left)>>1); if(nums[mid] > target){ right = mid-1; }else{ left = mid+1; /*这里有点疑问,就是如果是等于target,且nums中有多个target时,那么此时left可能是处于中间的target的位置。 这样的话,还要left = mid+1,显然就错过了最左侧target的下标。
其实,没有必要担心这个问题,因为nums是int型数组,不会等于terget的。 */ } } } }
针对上面的疑问,我加了点输出log,debug一下就明白了:
package Top100; import java.util.Arrays; class Top1 { public static int[] searchRange(int[] nums, int target) { if(nums==null || nums.length<=0){ return new int[]{-1,-1}; } Arrays.sort(nums); for (int i = 0; i < nums.length; i++) { System.out.printf(nums[i]+" "); } System.out.println((target - 0.5f)+" "+(target + 0.5f));//4.5,5.5 int left = binarySearch(nums,target - 0.5f); int right = binarySearch(nums,target + 0.5f); System.out.println(left+" "+right); if(left == right){ return new int[]{-1,-1}; }else{ return new int[]{left+1,right-1}; } } public static int binarySearch(int[] nums, float target){ int left = 0; int right = nums.length-1; while(left<right){ System.out.println(left+" "+right+" "+((right-left)>>1)); int mid = left+((right-left)>>1); if(nums[mid] > target){ right = mid-1; }else{ left = mid+1; } } return right; } public static void main(String[] args) { int[] nums = {1,3,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,6,8,9}; int patten = 5; int[] ret = searchRange(nums,patten); System.out.println(ret[0]+"--"+ret[1]); } }
输出:
1 3 4 4 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 6 8 9 4.5 5.5 0 23 11 12 23 5 12 16 2 12 13 0 0 23 11 12 23 5 18 23 2 21 23 1 13 21 14--20
Over....