这道题用二分法解决
不过大部分人(加上我)就算知道了用二分法解题,也还是无从下手吧,因为这个题的只要难点是找重复数字的左右边界,**只要找到了左边界(left)和右边界(right),就可以用right-left-1求出重复数字的长度。**这个应该不难理解,因为数组是有序的,重复数字是连续的,所以重复数字是一段一段的。
输入: nums = [5,7,7,8,8,10], target = 8
输出: 2
先上代码,让大家看一下。
class Solution {
public int search(int[] nums, int target) {
int i=0,j=nums.length-1;
// 找右边界
while(i<=j){
int m=(i+j)/2;
if(target>=nums[m])
i=m+1;
else
j=m-1;
}
int right=i;//j=i-1;
if(j>=0&&nums[j]!=target) return 0;
i=0;
j=nums.length-1;
//找左边界
while(i<=j){
int m=(i+j)/2;
if(target>nums[m])
i=m+1;
else
j=m-1;
}
int left=j;//i-j+1
return right-left-1;
}
}
二分法
在循环里面,是拿target与中间值m不断做比较来确定边界的。
i是左边界,j是右边界。
此时这个循环里面是找左右边界
1.target>中间值,执行的是i=m+1,左边界变化,右边界不变。
2.target<中间值,执行的是j=m-1,右边界变化,左边界不变。
3.target=中间值,
如果是找右边界,执行i=m+1
如果是找左边界,执行j=m-1
如果是找左边界,循环完之后i是右边界
如果是找右边界,循环完之后j是左边界
是不是很奇妙,没错,不信可以手动遍历一下,不论是求左边界还是右边界,最后有一步i和j相遇(指向同一元素),如果是求左边界(i和j则最后一步指向左边界,即重复数字的前一个数)
如果是求右边界(i和j则最后一步指向右边界,即重复数字的后一个数)
然后下一步i或者j(看求的是哪个边界)移动跳出循环,不动的就是左边界或者右边界(看求的是哪个边界.)
大家可以手动遍历一下,就会很清晰整个过程了。