面试算法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;
    }
}
相关推荐
Forever Nore41 分钟前
LeetCode 1 两数之和
算法·leetcode·职场和发展
To_OC1 小时前
LC 3 无重复字符的最长子串:从入门滑动窗口到优化写法,再也不怕面试官追问
javascript·算法·leetcode
(Charon)1 小时前
【C++】多线程死锁:产生原因、复现与解决方法
开发语言·c++·算法
lucas_AI2 小时前
ConfBench:大模型的「我很有把握」,到底能不能信?
人工智能·算法
oier_Asad.Chen2 小时前
【洛谷题解/AcWing题解/真题】洛谷P2330【SCOI2005】繁忙的都市(Kruskal算法的再探究))
c++·算法·贪心算法·图论·最小生成树·kruskal
青 春 记 忆5 小时前
LeetCode 53. 最大子数组和|Python 解法详解
python·算法·leetcode
豆瓣鸡5 小时前
算法日记 - Day10
算法
戴西软件5 小时前
戴西CAxWorks.VPG车辆工程仿真软件技术解析(上)——安全仿真体系的自动化构建
运维·网络·数据库·人工智能·算法·安全·自动化
zander2585 小时前
4. 寻找两个正序数组的中位数:用分割点代替合并
数据结构·算法
Kisorge5 小时前
【电机控制器】 基于STSPIN32G4的FOC控制
stm32·嵌入式硬件·算法