Java利用binarySearch实现lower_bound与upper_bound以及partition_point

想法来源

\quad\quad lower_boundupper_bound都是C++<algorithm>头文件提供的两个函数,用于分别查找大于等于以及严格大于给定值的最小下标,具体图示可见hacking cpp网站
Hacking Cpp网站图示

\quad\quad 而在使用Rust刷题的过程中,我经常使用partition_point来完成类似的功能,而点开partition_point源码实现,发现其底层基于二分查找实现。
Partition Point函数的功能实现
\quad\quad 于是产生了一个想法:既然Java提供了binarySearch函数,那么是否可以遵循类似的思路,从binarySearch函数中构造一个lowerBound函数以及upperBound函数呢?

代码实现

实现思路

\quad\quad 重点在于修改binarySearch的自定义ComparatorbinarySearch会利用Comparator比较midValue与给定的key的大小,从而决定二分过程中左右边界的移动。而我们所需要做的就是根据upper_boundlower_bound的函数逻辑,重写这个Comparator
\quad\quad 由于重写的Comparator并没有给出相等逻辑(其实对于upper_bound根本给不出相等逻辑判定,因为很难知道下一个严格大于给定数字的数值到底是多大),所以binarySearch给出的其实是所谓的插入坐标,是一个负数,因此最后需要转换一下这个插入坐标。

lowerBound实现

private static <T extends Comparable> int lowerBound(T[] arr, T key) {
        int index = Arrays.binarySearch(arr, key, new Comparator<T>() {
            final int LESS = -1;
            final int GREATER = 1;

            @Override
            public int compare(T midValue, T key) {
                if (midValue.compareTo(key) < 0) {
                    return LESS;
                } else {
                    return GREATER;
                }
            }
        });

        return -(index+1);
    }

upperBound实现

private static <T extends Comparable> int upperBound(T[] arr, T key) {
        int index = Arrays.binarySearch(arr, key, new Comparator<T>() {
            final int LESS = -1;
            final int GREATER = 1;
            @Override
            public int compare(T midValue, T key) {
                if (midValue.compareTo(key) <= 0) {
                    return LESS;
                } else {
                    return GREATER;
                }
            }
        });

        return -(index+1);
    }

partitionPoint实现

private static <T> int partitionPoint(T[] arr, Predicate pred) {
    int index = Arrays.binarySearch(arr, 0, (midValue, dummy) -> {
        if (pred.test(midValue)) {
            return -1;
        } else {
            return 1;
        }});

    return -(index+1);
}

\quad\quad 整体逻辑已经与rust中的partition_point函数较为接近了。不过binarySearchkey形参即待查找对象已经没有用了,顺带重写Comparator逻辑中,也只关心midValue,不再关心查找对象key
Rust中的partition_point函数

调用结果

lowerBoundupperBound调用

public class Main {
    public static void main(String[] args) {
        Integer[] arr = {1, 2, 3, 3, 3, 4, 5, 6};
        int key = 3;

        int i = upperBound(arr, key);
        System.out.println("Upper bound index is " + i);
        i = lowerBound(arr, key);
        System.out.println("Lower bound index is " + i);
    }
}
Upper bound index is 5		# 即`arr[5]` = 4, 第一个严格大于3的数字下标
Lower bound index is 2		# 即`arr[2]` = 3, 第一个大于等于3的数字下标

partitionPoint调用

public class Main {
    public static void main(String[] args) {
        Integer[] v = {1, 2, 3, 4, 5, 6, 7};
        int i = partitionPoint(v, x -> (Integer) x < 5);
        System.out.println("Returns the index of the partition point according to the given predicate (the index of the first element of the second partition):");
        System.out.println(i);

        i = partitionPoint(v, x -> (Integer) x < 100);
        System.out.println("If all elements of the slice match the predicate, including if the slice is empty, then the length of the slice will be returned:");
        System.out.println(i);
    }
}
Returns the index of the partition point according to the given predicate (the index of the first element of the second partition):
4
If all elements of the slice match the predicate, including if the slice is empty, then the length of the slice will be returned:
7

\quad\quad 整个调用例与Rust std docs中的例子一致,结果也相符。
Rust Docs中的解释

最后总结

\quad\quad 声明

本程序纯粹是出于兴趣的“造轮子”行为,并不承诺以上算法具有很好的鲁棒性和较高的性能表现!不喜勿喷。

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值