面试算法35:最小时间差

题目

给定一组范围在00:00至23:59的时间,求任意两个时间之间的最小时间差。例如,输入时间数组["23:50","23:59","00:00"],"23:59"和"00:00"之间只有1分钟的间隔,是最小的时间差。

分析

这个题目最直观的解法是求出任意两个时间的间隔,然后比较得出最小的时间差。如果输入n个时间,那么需要计算每个时间与另外n-1个时间的间隔,这种蛮力法需要O(n2)的时间。

上述解法的一个优化方法是把n个时间排序。排序之后只需要计算两两相邻的时间之间的间隔,这样就只需要计算O(n)个时间差。由于对n个时间进行排序通常需要O(nlogn)的时间,因此这种优化算法的总体时间复杂度是O(nlogn)。

这里有一个特殊情况值得注意。如果把输入的时间数组["23:50","23:59","00:00"]排序,就可以得到["00:00","23:50","23:59"]。时间00:00和23:50之间的间隔是1430分钟,而23:50和23:59之间的间隔是9分钟。由于排序之后的第1个时间00:00也可能是第2天的00:00,它和前一天的23:59之间的间隔只有1分钟。也就是说,在计算最小时间差时,需要把排序之后的第1个时间当作第2天的时间(即加上24小时)与最后一个时间之间的间隔也考虑进去。

接着思考如何做进一步优化。前面的算法主要将时间花在排序上面,那么排序是否可以避免?排序是为了计算相邻的两个时间的节点,所以用一个表示时间的数组也可以达到这个目的。

一天有24小时,即1440分钟。如果用一个长度为1440的数组表示一天的时间,那么数组下标为0的位置对应时间00:00,下标为1的位置对应时间00:01,以此类推,下标为1439的位置对应23:59。数组中的每个元素是true或false的标识,表示对应的时间是否存在于输入的时间数组中。

有了这个辅助数组,就只需要从头到尾扫描一遍,相邻的两个为true的值表示对应的两个时间在输入时间数组中是相邻的。例如,输入时间数组["23:50","23:59","00:00"],数组中只有下标为0、1430和1439这3个位置的值为true,其他位置的值都是false。

由于数组的下标对应的是时间,因此两个时间之间的时间差就是它们在数组中对应的下标之差。23:50和23:59之间相隔9分钟,它们在数组中的下标之差也是9。

java 复制代码
public class Test {
    public static void main(String[] args) {
        List<String> timePoints = Arrays.asList("23:50", "23:59", "00:00");
        int result = findMinDifference(timePoints);
        System.out.println(result);
    }

    public static int findMinDifference(List<String> timePoints) {
        if (timePoints.size() > 1440) {
            return 0;
        }

        boolean[] minuteFlags = new boolean[1440];
        for (String time : timePoints) {
            String[] t = time.split(":");
            int min = Integer.parseInt(t[0]) * 60 + Integer.parseInt(t[1]);
            if (minuteFlags[min]) {
                return 0;
            }

            minuteFlags[min] = true;
        }

        return helper(minuteFlags);
    }

    private static int helper(boolean[] minuteFlags) {
        int minDiff = minuteFlags.length - 1;
        int prev = -1;
        int first = minuteFlags.length - 1;
        int last = -1;
        for (int i = 0; i < minuteFlags.length; i++) {
            if (minuteFlags[i]) {
                if (prev >= 0) {
                    minDiff = Math.min(i - prev, minDiff);
                }

                prev = i;
                first = Math.min(i, first);
                last = Math.max(i, last);
            }
        }

        minDiff = Math.min(first + minuteFlags.length - last, minDiff);
        return minDiff;
    }
}
相关推荐
We་ct2 分钟前
LeetCode 56. 合并区间:区间重叠问题的核心解法与代码解析
前端·算法·leetcode·typescript
Lionel6897 分钟前
分步实现 Flutter 鸿蒙轮播图核心功能(搜索框 + 指示灯)
算法·图搜索算法
小妖66611 分钟前
js 实现快速排序算法
数据结构·算法·排序算法
xsyaaaan13 分钟前
代码随想录Day30动态规划:背包问题二维_背包问题一维_416分割等和子集
算法·动态规划
千寻girling35 分钟前
Koa.js 教程 | 一份不可多得的 Node.js 的 Web 框架 Koa.js 教程
前端·后端·面试
程序员清风43 分钟前
北京回长沙了,简单谈谈感受!
java·后端·面试
zheyutao1 小时前
字符串哈希
算法
A尘埃1 小时前
保险公司车险理赔欺诈检测(随机森林)
算法·随机森林·机器学习
网络安全-杰克2 小时前
2026面试自动化测试面试题【含答案】
自动化测试·软件测试·面试·职场和发展
大江东去浪淘尽千古风流人物2 小时前
【VLN】VLN(Vision-and-Language Navigation视觉语言导航)算法本质,范式难点及解决方向(1)
人工智能·python·算法