题目
给定一个 24 小时制(小时:分钟 HH:MM)的时间列表,找出列表中任意两个时间的最小时间差并以分钟数表示。
数据范围
2 <= timePoints.length <= 2 * 104
timePoints[i] 格式为 HH:MM
样例
输入 1
timePoints = ["23:59","00:00"]
输出 1
1
输入 2
timePoints = ["00:00","23:59","00:00"]
输出 2
0
关键逻辑
对部分情况提前结束
根据题意,一天只有 24 x 60 = 1440 分钟,即使每分钟一个时间点,那么只要数组长度超过 1440,则必有两个时间点相同,此时可直接判定最小时间差为 0,这就是所谓的鸽巢原理。
排序
目前我使用的是直接对字符串进行排序,也可以先全部转换为分钟数来排序。相对于插入排序,我选择了希尔排序,每次缩小增量为 2,以 LeetCode 为例,插入排序替换为希尔排序可缩短 4ms 的运行时间。
时间比较细节
经排序以后,可直接比较时间差,但是别忘了最小时间差有可能出现在头尾,即 头时间 + 24小时 - 尾时间,此时可先预先比较这个时间并设置为最小时间。
代码
class Solution {
public int findMinDifference(List timePoints) {
/*
* 鸽巢原理,如果时间点数组超过 1440。
* 由于一天有 24 x 60 = 1440 分钟,因此必有两个相同时间。
* 此时最小时间必定是 0。
*/
int length = timePoints.size();
if (length > 1440) {
return 0;
}
String[] timeArray = timePoints.toArray(new String[0]);
// 希尔排序
for (int i = length >> 1; i > 0; i >>= 1) {
for (int j = i; j < length; j++) {
int k = j - i;
String time = timeArray[j];
for (; k > -1; k -= i) {
if (time.compareTo(timeArray[k]) < 0) {
timeArray[k + i] = timeArray[k];
} else {
break;
}
}
timeArray[k + i] = time;
}
}
// 文本时间转化分钟数
String[] timeSplit = timeArray[0].split(":");
int timeMinute = Integer.parseInt(timeSplit[0]) * 60 + Integer.parseInt(timeSplit[1]);
// 假设最小时间是头时间 + 24 小时(1440 分钟) - 尾时间
timeSplit = timeArray[length - 1].split(":");
timeMinute = timeMinute + 1440 - (Integer.parseInt(timeSplit[0]) * 60 + Integer.parseInt(timeSplit[1]));
int minMinute = timeMinute;
for (int i = 0; i < length - 1; i++) {
timeSplit = timeArray[i + 1].split(":");
timeMinute = Integer.parseInt(timeSplit[0]) * 60 + Integer.parseInt(timeSplit[1]);
timeSplit = timeArray[i].split(":");
timeMinute -= Integer.parseInt(timeSplit[0]) * 60 + Integer.parseInt(timeSplit[1]);
if (timeMinute < minMinute) {
minMinute = timeMinute;
}
}
return minMinute;
}
}