自学内容网 自学内容网

力扣 2080. 区间内查询数字的频率 离散化 二分 开区间 左闭右开区间 lowerBound

Problem: 2080. 区间内查询数字的频率
在这里插入图片描述

在这里插入图片描述

👨‍🏫 参考题解
👨‍🏫 参考视频

在这里插入图片描述

🍚 左闭右开二分

class RangeFreqQuery {
    private final Map<Integer, List<Integer>> pos = new HashMap<>();

    public RangeFreqQuery(int[] arr) {
        for (int i = 0; i < arr.length; i++) {
             //初始化时,存放每个元素出现的下标位置,这个list本身已经是有序的,因为我们是按照下标开始存进去的,存的也是下标
            pos.computeIfAbsent(arr[i], k -> new ArrayList<>()).add(i);
        }
    }

    public int query(int left, int right, int value) {
        List<Integer> a = pos.get(value);
        if (a == null) {
            return 0;
        }
        return lowerBound(a, right + 1) - lowerBound(a, left);
    }

    // 开区间写法
    // 请看 https://www.bilibili.com/video/BV1AP41137w7/
    // 找到第一个 >= target 的下标,没有则返回数组长度
    private int lowerBound(List<Integer> a, int target) {
        // 左闭右开区间 [left, right)
        int left = 0;
        int right = a.size();
        while (left < right) { // 区间不为空
            int mid = (left + right) >>> 1;
            if (a.get(mid) < target) {
                left = mid + 1; // 范围缩小到 [mid + 1, right)
            } else {
                right = mid; // 范围缩小到 [left, mid)
            }
        }
        return left; // right 是最小的满足 a[right] >= target 的下标
    }
}

🍚 开区间二分

class RangeFreqQuery {
    private final Map<Integer, List<Integer>> pos = new HashMap<>();

    public RangeFreqQuery(int[] arr) {
        for (int i = 0; i < arr.length; i++) {
             //初始化时,存放每个元素出现的下标位置,这个list本身已经是有序的,因为我们是按照下标开始存进去的,存的也是下标
            pos.computeIfAbsent(arr[i], k -> new ArrayList<>()).add(i);
        }
    }

    public int query(int left, int right, int value) {
        List<Integer> a = pos.get(value);
        if (a == null) {
            return 0;
        }
        return lowerBound(a, right + 1) - lowerBound(a, left);
    }

    // 开区间写法
    // 请看 https://www.bilibili.com/video/BV1AP41137w7/
    private int lowerBound(List<Integer> a, int target) {
        // 开区间 (left, right)
        int left = -1;
        int right = a.size();
        while (left + 1 < right) { // 区间不为空
            // 循环不变量:
            // a[left] < target
            // a[right] >= target
            int mid = (left + right) >>> 1;
            if (a.get(mid) < target) {
                left = mid; // 范围缩小到 (mid, right)
            } else {
                right = mid; // 范围缩小到 (left, mid)
            }
        }
        return left; // right 是最小的满足 a[right] >= target 的下标
    }
}

原文地址:https://blog.csdn.net/lt6666678/article/details/144783151

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!