LC825

原题:适龄的朋友

三个条件可以转换成&的形式

可以知道第三个条件是多余的,必然能满足。

我们可以通过先对年龄进行排序,然后通过二分查找满足条件的左右边界

/**
     * 解法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:双指针