LC825
原题:适龄的朋友
三个条件可以转换成&的形式
- y > 0.5*x+7
- y <= x
-
y <= 100 x >= 100
可以知道第三个条件是多余的,必然能满足。
我们可以通过先对年龄进行排序,然后通过二分查找满足条件的左右边界
/**
* 解法2,经过梳理后的数学公式可以简化成 x>=y>0.5*x+7,
* <p>
* y<=x
* y>0.5x+7
*
* 时间复杂度O(nlogn)
*/
public int numFriendRequests2(int[] ages) {
//排序
Arrays.sort(ages);
int cnt = 0;
for (int i = 0; i < ages.length; i++) {
//二分查找找到满足条件的y值,需要左右两边同时查找
int left = searchLeft(ages, i);
if (left >= 0) {
//[idx,i)
cnt += i - left;
}
int right = searchRight(ages, i);
if (right > i) {
cnt += right - i;
}
}
return cnt;
}
//二分查找左边界
private int searchLeft(int[] ages, int idx) {
if (idx == 0) {
return -1;
}
double value = 0.5 * ages[idx] + 7;
if (ages[idx - 1] <= value) {
return -1;
}
int l = 0, r = idx - 1;
while (l < r) {
int mid = l + (r - l) / 2;
if (ages[mid] > value) {
r = mid;
} else {
l = mid + 1;
}
}
return l;
}
//右边界其实就是找相等的数字的右边界,y<=x,y>0.5x+7,右边也有可能满足这个条件。y==x,且y>0.5x+7,最终换算得到y>14
private int searchRight(int[] ages, int idx) {
//上面条件y>14
if (ages[idx] <= 14) {
return -1;
}
int l = idx, r = ages.length - 1;
while (l < r) {
int mid = l + (r - l + 1) / 2;
if (ages[mid] == ages[idx]) {
l = mid;
} else {
r = mid - 1;
}
}
return l;
}
TODO:双指针