Java判断范围型的数据是否存在重叠(数值类型、日期类型)

为什么写这么一篇文章呢?

遇到了个问题,同一天可以输入多个时间段,但是每个时间段的时间不能出现重叠。

纳尼,这不就是判断数据返回是否有重叠的变种嘛~

简单,开搞

数字范围是否重叠判断

这里以int类型为例了,其它的也都类似

核心方法

    /**
     * @param start1 第一个数据开始时间
     * @param end1   第一个数据结束时间
     * @param start2 第二个数据开始时间
     * @param end2   第二个数据结束时间
     * @return true:发生重叠  false:未发生重叠
     */
    public static boolean isIntersect(int start1, int end1, int start2, int end2) {
        return Math.max(start1, start2) <= Math.min(end1, end2);
    }

4个参数start1-end1代表第一组范围,start2-end2代表第二组范围;

Math.max(start1, start2) <= Math.min(end1, end2)使用Math.maxMath.min可以无视第一组数据和第二组数据的顺序,只比较是否重叠,<= 代表0-1后面不能是1-3,只能是2-3;如果想要1-3的效果把=去掉即可,后面会有演示。

核心方法非常简单,那我们造一组伪数据测试一下吧。

测试数据

先来一组错误数据吧

[
  {"startNum": 0, "endNum": 100},
  {"startNum": 100, "endNum": 500},
  {"startNum": 400, "endNum": 1000},
  {"startNum": 1001, "endNum": 9999}
]

测试方法


    public static void main(String[] args) {
        String str = "[\n" +
                "  {\"startNum\": 0, \"endNum\": 100},\n" +
                "  {\"startNum\": 100, \"endNum\": 500},\n" +
                "  {\"startNum\": 500, \"endNum\": 1000},\n" +
                "  {\"startNum\": 1001, \"endNum\": 9999}\n" +
                "]";
        JSONArray array = JSON.parseArray(str);
        for (int i = 0; i < array.size(); i++) {
            for (int j = i + 1; j < array.size(); j++) {
                boolean isOk = isIntersect(
                        handleStr(array.getJSONObject(i).getString("startNum")),
                        handleStr(array.getJSONObject(i).getString("endNum")),
                        handleStr(array.getJSONObject(j).getString("startNum")),
                        handleStr(array.getJSONObject(j).getString("endNum")));
                if (isOk) {
                    System.out.println("no " + j + " and no " + (j + 1) + " is intersect");
                    System.out.println("or say, "
                            + array.getJSONObject(i).getString("startNum")
                            + " to " + array.getJSONObject(i).getString("endNum")
                            + " and " + array.getJSONObject(j).getString("startNum")
                            + " to " + array.getJSONObject(j).getString("endNum")
                            + " is intersect");

                    System.out.println("\n");
                }
            }
        }
    }

答案还是很清晰的哈~

image-20240704103426928

数字范围效果完成了。数值类的都类似哈

时间范围是否重叠判断

时间有很多种,我们一种一种的来说,实现都一样,重要的是思想

首先来看一下下面这种格式,搞个错误数据吧

  [
    {"startTime": "00:00", "endTime": "01:00"},
    {"startTime": "01:00", "endTime": "02:00"},
    {"startTime": "01:00", "endTime": "02:00"},
    {"startTime": "08:00", "endTime": "22:00"},
    {"startTime": "20:00", "endTime": "24:00"}
  ]

因为01:00是重叠的,所以我们把上面核心方法的=去掉。如下

    /**
     * @param start1 第一个数据开始时间
     * @param end1   第一个数据结束时间
     * @param start2 第二个数据开始时间
     * @param end2   第二个数据结束时间
     * @return true:发生重叠  false:未发生重叠
     */
    public static boolean isIntersect(int start1, int end1, int start2, int end2) {
        return Math.max(start1, start2) < Math.min(end1, end2);
    }

接下来就很简单了,把时间处理成数据类型就可以了,下面看一下处理的方法

    public static int handleStr(String str) {
        str = str.replace(":", "");
        return Integer.parseInt(str);
    }

来一起看一下运行结果吧


    public static void main(String[] args) {
        String data = "  [\n" +
                "    {\"startTime\": \"00:00\", \"endTime\": \"01:00\"},\n" +
                "    {\"startTime\": \"01:00\", \"endTime\": \"02:00\"},\n" +
                "    {\"startTime\": \"01:00\", \"endTime\": \"02:00\"},\n" +
                "    {\"startTime\": \"08:00\", \"endTime\": \"22:00\"},\n" +
                "    {\"startTime\": \"20:00\", \"endTime\": \"24:00\"}\n" +
                "  ]";
        JSONArray array = JSON.parseArray(data);
        for (int i = 0; i < array.size(); i++) {
            for (int j = i + 1; j < array.size(); j++) {
                boolean isOk = isIntersect(
                        handleStr(array.getJSONObject(i).getString("startTime")),
                        handleStr(array.getJSONObject(i).getString("endTime")),
                        handleStr(array.getJSONObject(j).getString("startTime")),
                        handleStr(array.getJSONObject(j).getString("endTime")));
                if (isOk) {
                    System.out.println("no " + j + " and no " + (j + 1) + " is intersect");
                    System.out.println("or say, "
                            + array.getJSONObject(i).getString("startTime")
                            + " to " + array.getJSONObject(i).getString("endTime")
                            + " and " + array.getJSONObject(j).getString("startTime")
                            + " to " + array.getJSONObject(j).getString("endTime")
                            + " is intersect");

                    System.out.println("\n");
                }
            }
        }
    }

image-20240704152655730

对于时间类型,下面格式如何比较

  [
    {"startTime": "2024-07-04 00:00:00", "endTime": "2024-07-04 10:00:00"},
    {"startTime": "2024-07-04 10:00:00", "endTime": "2024-07-04 12:00:00"},
    {"startTime": "2024-07-04 12:00:00", "endTime": "2024-07-04 13:00:00"},
    {"startTime": "2024-07-04 12:00:00", "endTime": "2024-07-04 18:00:00"},
    {"startTime": "2024-07-04 17:00:00", "endTime": "2024-07-04 23:00:00"}
  ]

其实直接将时间转为时间戳来比较就可以了,完整代码如下:

    public static void main(String[] args) {
        String data = "[\n" +
                "    {\"startTime\": \"2024-07-04 00:00:00\", \"endTime\": \"2024-07-04 10:00:00\"},\n" +
                "    {\"startTime\": \"2024-07-04 10:00:00\", \"endTime\": \"2024-07-04 12:00:00\"},\n" +
                "    {\"startTime\": \"2024-07-04 12:00:00\", \"endTime\": \"2024-07-04 13:00:00\"},\n" +
                "    {\"startTime\": \"2024-07-04 12:00:00\", \"endTime\": \"2024-07-04 18:00:00\"},\n" +
                "    {\"startTime\": \"2024-07-04 17:00:00\", \"endTime\": \"2024-07-04 23:00:00\"}\n" +
                "  ]";
        JSONArray array = JSON.parseArray(data);
        for (int i = 0; i < array.size(); i++) {
            for (int j = i + 1; j < array.size(); j++) {
                boolean isOk = isIntersect(
                        handleDate(array.getJSONObject(i).getString("startTime")),
                        handleDate(array.getJSONObject(i).getString("endTime")),
                        handleDate(array.getJSONObject(j).getString("startTime")),
                        handleDate(array.getJSONObject(j).getString("endTime")));
                if (isOk) {
                    System.out.println("no " + j + " and no " + (j + 1) + " is intersect");
                    System.out.println("or say, "
                            + array.getJSONObject(i).getString("startTime")
                            + " to " + array.getJSONObject(i).getString("endTime")
                            + " and " + array.getJSONObject(j).getString("startTime")
                            + " to " + array.getJSONObject(j).getString("endTime")
                            + " is intersect");

                    System.out.println("\n");
                }
            }
        }
    }

    /**
     * @param start1 第一个数据开始时间
     * @param end1   第一个数据结束时间
     * @param start2 第二个数据开始时间
     * @param end2   第二个数据结束时间
     * @return true:发生重叠  false:未发生重叠
     */
    public static boolean isIntersect(long start1, long end1, long start2, long end2) {
        return Math.max(start1, start2) < Math.min(end1, end2);
    }

    @SneakyThrows
    public static long handleDate(String str) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        return sdf.parse(str).getTime();
    }

看一下测试结果

image-20240704154200906

总结

实际很简单,就是把需要校验的数据两两比较就可以了,总体思想就是把数据转为数值类型,然后进行比较就可以了。如果对你有帮助,记得点个关注哈~

<think>好的,我需要回答用户关于蓝桥杯Java B组常考算法类型的问题。首先,我得回忆一下蓝桥杯的考试大纲和常见考点。根据用户提供的引用内容,引用[2]提到蓝桥杯涉及思维、基础数学知识、打表、Java语言熟悉、搜索、模拟、Java容器类和时间复杂度分析。这些可以作为主要的算法类型分类基础。 接下来,我需要将这些内容具体化。比如基础数学知识可能包括快速幂、大数运算等。快速幂在引用[3]中有详细说明,而大数处理则提到了BigInteger类,引用[4]中的例子也验证了这一点。所以这部分需要作为数学相关算法列出。 然后是搜索算法,蓝桥杯常见的应该包括深度优先搜索(DFS)和广度优先搜索(BFS),以及可能的剪枝优化。模拟题通常要求按照题目描述逐步实现,可能涉及复杂逻辑处理,比如日期计算或者游戏规则模拟,引用[2]中提到了模拟这一点。 动态规划也是重点,比如背包问题、路径问题等。需要结合经典例题来说明。贪心算法可能涉及区间调度或最优选择问题,但需要与动态规划区分开。 图论部分可能包括最短路径、最小生成树等算法,比如Dijkstra或Prim算法。数据结构方面,用户引用[1]提到使用HashSet、TreeMap、ArrayList.sort()和HashMap,这些容器类在解题中很常用,所以需要强调它们的应用场景。 字符串处理方面,可能涉及KMP算法、回文判断或正则表达式,但根据引用内容,这部分可能需要结合具体例子。其他技巧如打表法,预处理结果直接查表,这在时间紧迫时很有用,引用[2]提到打表法,所以需要包含进去。 时间复杂度分析也是必须的,引用[2]和[3]都提到了这一点,尤其是快速幂的时间复杂度是O(log n),对比暴力解法更高效。因此,在准备时需要能够分析算法的时间复杂度,选择合适的方法。 现在需要将这些内容组织成结构清晰的回答,按照类别分点说明,每个类别下给出具体算法或技术,并结合引用中的例子。比如在数学部分提到快速幂和大数运算,并引用[3]和[4]。在容器类部分引用[1]中的内容。 同时,用户要求生成相关问题,我需要根据每个算法类型提出相关问题,比如如何实现快速幂、DFS和BFS的区别等。问题需要覆盖各个主要考点,帮助用户进一步复习。 最后,确保回答符合格式要求:行内公式用$...$,独立公式用$$...$$,正确使用引用标识。例如,在快速幂部分引用[3],在容器类引用[1]。检查是否有遗漏的考点,比如排序算法可能涉及快速排序,但用户提供的引用中没有详细说明,可能需要简要提及,但重点放在用户提供的引用内容上。 总结下来,回答的结构应该是分点列出各个算法类型,每个类型下具体说明,并附上相关引用。然后生成相关问题,覆盖每个主要部分,帮助用户深入理解。</think>### 蓝桥杯 Java B组常考算法类型总结 #### 1. **基础数学与数论** - **快速幂算法**:用于高效计算大指数幂,时间复杂度为$O(\log n)$,常用于模运算场景[^3]。 ```java public static long binpow(long a, long b) { long res = 1; while (b > 0) { if ((b & 1) == 1) res = res * a; a = a * a; b >>= 1; } return res; } ``` - **大数运算**:当数值超出`long`范围时,需使用`BigInteger`类(如高精度加减乘除)[^4]。 - **质数筛法**:埃氏筛、欧拉筛等。 - **模运算与同余方程**:如求解逆元、中国剩余定理。 #### 2. **搜索与回溯** - **DFS(深度优先搜索)**:用于全排列、组合、迷宫路径问题。 - **BFS(广度优先搜索)**:解决最短路径、层序遍历问题。 - **剪枝优化**:通过预判减少无效搜索,如数独问题中的可行性判断。 #### 3. **动态规划(DP)** - **经典问题**:背包问题(01背包、完全背包)、最长公共子序列、编辑距离。 - **状态转移方程设计**:如斐波那契数列的递推公式$f(n) = f(n-1) + f(n-2)$。 - **记忆化搜索**:递归+缓存,避免重复计算。 #### 4. **贪心算法** - **区间调度**:选择不重叠的区间最大化数量。 - **哈夫曼编码**:最小化带权路径长度。 #### 5. **图论** - **最短路径**:Dijkstra算法(单源无负权边)、Floyd-Warshall算法(多源)。 - **最小生成树**:Prim算法、Kruskal算法。 - **拓扑排序**:解决任务调度、依赖关系问题。 #### 6. **数据结构应用** - **Java容器类**: - 去重:`HashSet` - 排序:`TreeMap`或`ArrayList.sort()` - 映射关系:`HashMap`[^1] - **前缀和与差分**:用于区间求和问题优化。 - **并查集**:处理集合合并与连通性问题。 #### 7. **模拟与实现** - **复杂逻辑模拟**:如日期计算(闰年判断)、游戏规则实现。 - **输入输出优化**:使用`BufferedReader`替代`Scanner`加速读取[^4]。 #### 8. **字符串处理** - **KMP算法**:高效字符串匹配。 - **回文处理**:Manacher算法或中心扩展法。 #### 9. **其他技巧** - **打表法**:预处理结果直接查表,减少运行时计算量[^2]。 - **时间复杂度分析**:根据数据规模选择算法,如$n \leq 1e5$时需$O(n \log n)$算法。 --- ###
评论 23
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

笑小枫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值