题目地址:
https://www.lintcode.com/problem/last-position-of-target/description
给定一个数组,求target出现的最后的位置。若不存在则返回 − 1 -1 −1。
直接用二分法。代码如下:
public class Solution {
/**
* @param nums: An integer array sorted in ascending order
* @param target: An integer
* @return: An integer
*/
public int lastPosition(int[] nums, int target) {
// write your code here
if (nums == null || nums.length == 0) {
return -1;
}
int l = 0, r = nums.length - 1;
while (l < r) {
int m = l + (r - l + 1 >> 1);
if (nums[m] < target) {
l = m + 1;
} else if (nums[m] > target) {
r = m - 1;
} else {
l = m;
}
}
return nums[r] == target ? r : -1;
}
}
时间复杂度 O ( log n ) O(\log n) O(logn)。
尤其注意两个细节:
1、int m = l + (r - l + 1 >> 1);
为什么要在
r
−
l
+
1
r-l+1
r−l+1这里要写上
+
1
+1
+1,而不直接用
r
−
l
r-l
r−l?
答:原因是,下面的逻辑里有可能走到 l = m l=m l=m,而在 [ l , r ] [l,r] [l,r]只有两个数的时候, l = m l=m l=m并不能缩小区间,有可能会导致死循环;而 + 1 +1 +1以后,中点取的是靠右的,此时无论如何区间都会严格缩小,从而不会死循环。
2、return nums[r] == target ? r : -1;
为什么这里要写nums[r]
,可不可以写nums[l]
,还是两者都可以?
答:必须写nums[r]
,写nums[l]
是不正确的。原因是,只要while循环未结束,无论
r
r
r得到怎样的更新,都始终可以保证在
[
l
,
r
]
[l,r]
[l,r]区间之内,不会越出区间,原因是我们取的中点是靠右的,而while循环未终止意味着区间内还至少有两个数,这样一来,即使执行了r = m - 1
,
r
r
r也不会越出区间得到非法的数字。而如果写nums[l]
,则不能保证这一点,有可能
l
l
l取出区间(例如取到了
−
1
-1
−1,从而导致数组取到了非法的index)。