题解
- 题意:给定非递减整数数组
arr
, arr
中恰好有一个整数,它的出现次数超过数组元素总数的 25%。 - 题解:最简单的就是利用双指针设置一个
0.25*arr.length
大小的窗口,一位位往后遍历,这个几行代码就可以实现,O(n)
。
- 我们再看看题目,题目告诉我们,数组是排好序的,既然是因为数组是排好序的,就可以考虑二分法计数法。二分法计数是因为二分查找有两种,一种是找到重复数字第一次出现的位置,另一种是找到重复数据最后一次出现的位置,这也成为
lower_bound
和upper_bound
查找法。 - 这题如何套用二分计数呢,最直观的做法就是从前往后,对数组每个元素都进行二分计数,可是这种做法就是
O(nlogn)
的复杂度,反而增加了,那有什么更好的做法吗 - 再考虑一下,上面的做法其实多了很多没有必要的计算,因为大多元素出现的次数都是小于要求频率的,这就可以在遍历数据的时候进行筛选
- 我们可以考虑将遍历的跨度设置为
0.25*arr.length
,因为如果数据大于0.25*arr.length
次,一次循环跳动是不会筛除这个元素的,反之则可能会被删除,因此减少了大量没必要的运算,最后最多只需要进行4次二分查找,因此复杂度是O(logn)
- 实现:想法很简单,实现很恶心,要注意很多鸡毛蒜皮的边界条件
public int binarysearch(int[]arr, int target){
int l = 0;
int r = arr.length-1;
int s = 0;
int cnt = 0;
while(l<r){
int mid = (l+r+1)>>1;
if(arr[mid] <= target) l = mid;
else r = mid-1;
}
int posr = l;
l = 0;
r = arr.length-1;
while(l<r){
int mid = (l+r)>>1;
if(arr[mid] >= target) r = mid;
else l = mid+1;
}
int posl = r;
return posr-posl+1;
}
public int findSpecialInteger(int[] arr) {
int n = arr.length;
int quart = n/4+1;
int num = 0;
int j = 0;
while(j < n){
if(binarysearch(arr, arr[j]) >= quart) return arr[j];
j+=quart;
}
return num;
}
题目