539. 最小时间差 :「排序」&「计数」

简介: 539. 最小时间差 :「排序」&「计数」

网络异常,图片无法展示
|


题目描述



这是 LeetCode 上的 539. 最小时间差 ,难度为 中等


Tag : 「模拟」、「排序」、「哈希表」


给定一个 2424 小时制(小时:分钟 "HH:MM")的时间列表,找出列表中任意两个时间的最小时间差并以分钟数表示。


示例 1:


输入:timePoints = ["23:59","00:00"]
输出:1
复制代码


示例 2:


输入:timePoints = ["00:00","23:59","00:00"]
输出:0
复制代码


提示:


  • 2 <= timePoints <= 2 * 10^42<=timePoints<=2104
  • timePoints[i] 格式为 "HH:MM"


模拟(排序)



根据题意,我们需要找出「时钟盘」中的夹角最小的两个时间点,其中包括了分布在 00:00 左右两侧(横跨了一天)的时间点。


因此,一种简单的方式是对于每个 timePoints[i]timePoints[i],我们不仅记录「当天该时间点」对应的的偏移量,还记录「下一天该时间点」对应的偏移量。


处理所有的 timePoints[i]timePoints[i] 后,对偏移量进行排序,遍历找到所有相邻元素之间的最小值。


代码(感谢 @Benhao@🍭可乐可乐吗 同学提供的其他语言版本):


class Solution {
    public int findMinDifference(List<String> timePoints) {
        int n = timePoints.size() * 2;
        int[] nums = new int[n];
        for (int i = 0, idx = 0; i < n / 2; i++, idx += 2) {
            String[] ss = timePoints.get(i).split(":");
            int h = Integer.parseInt(ss[0]), m = Integer.parseInt(ss[1]);
            nums[idx] = h * 60 + m;
            nums[idx + 1] = nums[idx] + 1440;
        }
        Arrays.sort(nums);
        int ans = nums[1] - nums[0];
        for (int i = 0; i < n - 1; i++) ans = Math.min(ans, nums[i + 1] - nums[i]);
        return ans;
    }
}
复制代码

class Solution:
    def findMinDifference(self, timePoints: List[str]) -> int:
        n = len(timePoints) * 2
        nums, idx = [0] * n, 0
        for time in timePoints:
            h, m = int(time[:2]), int(time[-2:])
            nums[idx] = h * 60 + m
            nums[idx + 1] = nums[idx] + 1440
            idx += 2
        nums.sort()
        return min(nums[i + 1] - nums[i] for i in range(n - 1))
复制代码

func findMinDifference(timePoints []string) int {
    n := len(timePoints) * 2
    nums := make([]int, n)
    for i, idx := 0, 0; i < n / 2; i++ {
        ss := strings.Split(timePoints[i], ":")
        h, _ := strconv.Atoi(ss[0])
        m, _ := strconv.Atoi(ss[1])
        nums[idx] = h * 60 + m
        nums[idx + 1] = nums[idx] + 1440
        idx += 2
    }
    sort.Ints(nums)
    ans := nums[1] - nums[0];
    for i := 1; i < n - 1; i++ {
        if v := nums[i + 1] - nums[i]; v < ans {
            ans = v
        }
    }
    return ans
}
复制代码

class Solution {
public:
    int findMinDifference(vector<string>& timePoints) {
        int n = timePoints.size() * 2;
        vector<int> nums(n);
        for(int i = 0, idx = 0; i < n / 2; i++, idx += 2){
            string ss = timePoints[i];
            auto pos = ss.find(':');
            int h = stoi(ss.substr(0, pos)), m = stoi(ss.substr(pos + 1));
            nums[idx] = h * 60 + m;
            nums[idx + 1] = nums[idx] + 1440;
        }
        sort(nums.begin(), nums.end());
        int ans = nums[1] - nums[0];
        for(int i = 0; i < n - 1; i++){
            ans = min(ans, nums[i + 1] - nums[i]);
        }
        return ans;
    }
};
复制代码

int min(int a,int b){ return a > b ? b : a; }
int cmp(const void* a , const void* b){ return  (*(int*)a) - (*(int*)b); }
int findMinDifference(char ** timePoints, int timePointsSize){
    int n = timePointsSize * 2;
    int* nums = (int*) malloc(sizeof(int) * n);
    for(int i = 0, idx = 0; i < n / 2; i++, idx += 2){
        timePoints[i][2] = '\0';
        int h = atoi(timePoints[i]), m = atoi(timePoints[i] + 3);
        nums[idx] = h * 60 + m;
        nums[idx + 1] = nums[idx] + 1440;
    }
    qsort(nums, n, sizeof(nums[0]), cmp);
    int ans = nums[1] - nums[0];
    for(int i = 0; i < n - 1; i++){
        ans = min(ans, nums[i + 1] - nums[i]);
    }
    free(nums);
    nums = NULL;
    return ans;
}
复制代码


  • 时间复杂度:O(n\log{n})O(nlogn)
  • 空间复杂度:O(n)O(n)


模拟(哈希表计数)



利用当天最多只有 60 * 24 = 14406024=1440 个不同的时间点(跨天的话则是双倍),我们可以使用数组充当哈希表进行计数,同时根据「抽屉原理」,若 timePointstimePoints 数量大于 14401440,必然有两个相同时间点,用作剪枝。


然后找到间隔最小两个时间点,这种利用「桶排序」的思路避免了对 timePointstimePoints 所对应的偏移量进行排序,而 O(C)O(C) 的复杂度使得所能处理的数据范围没有上限。


代码:


class Solution {
    public int findMinDifference(List<String> timePoints) {
        int n = timePoints.size();
        if (n > 1440) return 0;
        int[] cnts = new int[1440 * 2 + 10];
        for (String s : timePoints) {
            String[] ss = s.split(":");
            int h = Integer.parseInt(ss[0]), m = Integer.parseInt(ss[1]);
            cnts[h * 60 + m]++;
            cnts[h * 60 + m + 1440]++;
        }
        int ans = 1440, last = -1;
        for (int i = 0; i <= 1440 * 2 && ans != 0; i++) {
            if (cnts[i] == 0) continue;
            if (cnts[i] > 1) ans = 0;
            else if (last != -1) ans = Math.min(ans, i - last);
            last = i;
        }
        return ans;
    }
}
复制代码


  • 时间复杂度:O(C)O(C)
  • 空间复杂度:O(C)O(C)


最后



这是我们「刷穿 LeetCode」系列文章的第 No.539 篇,系列开始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完。


在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。


为了方便各位同学能够电脑上进行调试和提交代码,我建立了相关的仓库:github.com/SharingSour…


在仓库地址里,你可以看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其他优选题解。

相关文章
|
5月前
1023 组个最小数 (20 分)
1023 组个最小数 (20 分)
|
6月前
最小操作次数问题
最小操作次数问题
44 1
|
6月前
leetcode-539:最小时间差
leetcode-539:最小时间差
30 0
|
4月前
|
C++
1984. 学生分数的最小差值C++
1984. 学生分数的最小差值C++
|
6月前
4.韩信点兵:有一个数,用3除余2;用5除余3;用7除余2,求满足条件的最小数
4.韩信点兵:有一个数,用3除余2;用5除余3;用7除余2,求满足条件的最小数
27 0
|
6月前
|
算法 Java 测试技术
连号区间数
连号区间数
56 0
随机1-100的数循环找出88的次数
随机1-100的数循环找出88的次数
87 0
|
算法
“计数”排序
“计数”排序
110 0
|
Python
一日一技:快速判断一个数属于等间隔范围中的位置
一日一技:快速判断一个数属于等间隔范围中的位置
97 0