Java每日一题——>剑指 Offer II 035. 最小时间差(三解,蛮力,排序,哈希)
文章目录
- 题目
- 题解1(蛮力法)
- 代码实现
- 复杂度分析
- 题解2(排序)
- 代码实现
- 复杂度分析
- 题解3(哈希表)
- 代码实现
- 复杂度分析
题目
这是LeetCode上的 [035,最小时间差],难度为 [中等]
给定一个 24 小时制(小时:分钟 “HH:MM”)的时间列表,找出列表中任意两个时间的最小时间差并以分钟数表示。
示例 1:
输入:timePoints = ["23:59","00:00"]
输出:1
示例 2:
输入:timePoints = ["00:00","23:59","00:00"]
输出:0
提示:
- 2 <= timePoints <= 2 * 104
- timePoints[i] 格式为 "HH:MM"
题解1(蛮力法)
由于时间列表的时间是没有大小顺序的,若不对时间进行排序,则需要使用蛮力法。
蛮力法就是在遍历时间列表时,让当前时间与当前时间后面的每个时间都进行相减得到时间差,时间差最短的即为最小时间
特别地,当时间列表的长度超过1440(24小时有1440分钟),这说明时间列表中最少有两个相同的时间,相同的时间我们按当天的时间处理,则时间差为0即为最小时间差
同样的,在遍历时间列表时,如果发现当前时间与当前时间后面的某个时间相同,则我们认为最小时间差为0
特别地,如果时间列表的存在时间00:00,则有两种情况的可能,当天的00:00或第二天的00:00,而上面地算法,默认认为是当天的00:00
因此我们还需要把第二天的时间00:00也考虑进去,换句话说就是把时间列表的最早的时间加上1440(24小时)变成第二天的时间,然后减去时间列表的最晚的一个时间得到时间差
需要注意的时,时间列表的时间是没有大小顺序的,所有相减的时间差可能为负值,故需要求绝对值
代码实现
class Solution {public int findMinDifference(List<String> timePoints) {// 若时间列表大于1440,则至少存在两个相等的时间,可以认为时间差为0if (timePoints.size() > 1440) {return 0;}// 记录最小时间差,初始为最大值int minDiff = 1439;// 遍历过程中的当前时间int currTime = -1;// 遍历过程中当前时间的后面所有时间int nextTime = -1;// 记录最小时间int first = 1439;// 记录最大时间int last = -1;// 遍历时间列表,遍历过程中让当前时间与当前时间后面的所有时间做时间差并记录最小的时间差for(int i = 0; i < timePoints.size(); i++) {String[] curr = timePoints.get(i).split(":");// 遍历过程的当前时间currTime = Integer.parseInt(curr[0]) * 60 + Integer.parseInt(curr[1]);// 当前时间后面的所有时间for (int j = i + 1; j < timePoints.size(); j++) {String[] next = timePoints.get(j).split(":");nextTime = Integer.parseInt(next[0]) * 60 + Integer.parseInt(next[1]);// 若当前时间与当前时间后面的某个时间相同,则时间差为0if (currTime == nextTime) {return 0;}minDiff = Math.min(Math.abs(nextTime - currTime), minDiff);first = Math.min(nextTime < currTime ? nextTime : currTime, first);last = Math.max(nextTime > currTime ? nextTime : currTime, last);}}/* 把最小的时间变成第二天的时间,然后减去最大的时间得到时间差若此时间差比最小时间时间差还小,则此时间差就是最小的时间差*/minDiff = Math.min(first + 1440 - last, minDiff);return minDiff;}
}
复杂度分析
假设时间列表的长度为n
时间复杂度
由于需要遍历时间列表,遍历过程中的当前时间需要和当前时间后面的所有结点做时间差,故时间复杂度为O(n2)
空间复杂度
由于声明的变量都是固定的,因此空间复杂度为O(1)
题解2(排序)
如果对时间进行排序,那么在遍历时间列表时,由于时间是排好序的,因此我们只需要让两两相邻的时间做时间差即可
特别地,当时间列表的长度超过1440,这说明时间列表中最少有两个相同的时间,相同的时间我们按当天的时间处理,则时间差为0即为最小时间差
同样的,在遍历时间列表算出分钟数时,如果发现集合已经包含此分钟数时,则说明有两个时间相同,则我们认为最小时间差为0
特别地,如果时间列表的存在时间00:00,则有两种情况的可能,当天的00:00或第二天的00:00,而上面地算法,默认认为是当天的00:00
因此我们还需要把第二天的时间00:00也考虑进去,换句话说就是把时间列表的最早的时间加上1440(24小时)变成第二天的时间,然后减去时间列表的最晚的一个时间得到时间差
代码实现
class Solution {public int findMinDifference(List<String> timePoints) {// 若时间列表大于1440,则至少存在两个相等的时间,可以认为时间差为0if (timePoints.size() > 1440) {return 0;}// 动态数组,存放时间ArrayList<Integer> timeList = new ArrayList<>();// 遍历时间列表,算出时间的分钟数并添加的集合中for (String timePoint : timePoints) {String[] split = timePoint.split(":");int time = Integer.parseInt(split[0]) * 60 + Integer.parseInt(split[1]);// 判断时间列表的时间是否已包含在集合中,若已包含,说明时间相同,则认为时间差为0if(timeList.contains(time)) {return 0;}timeList.add(time);}// 调用集合工具类对集合进行排序Collections.sort(timeList);// 存在最小时间差,初始为最大值int minDiff = 1439;// 存放遍历集合过程中的当前时间的前一个时间int pre = -1;// 存放最小的时间,即集合第一个元素int first = 1439;// 存放最大的时间,即集合最后一个元素int last = -1;// 遍历集合for (int i = 0; i < timeList.size(); i++) {int curr = timeList.get(i);/* 遍历过程的当前时间减去当前时间的前一个时间算出时间差,并于最小时间差比较求最小值* 第一个循环时,当前时间没有前一个时间,故不执行*/if (pre >= 0) {minDiff = Math.min(curr - pre, minDiff);}// 当前时间作为当前时间下一个时间的前一个时间pre = curr;// 求出最小时间first = Math.min(curr, first);// 求出最大时间last = Math.max(curr, last);}// 最小时间加上1440(24小时)变成第二天的时间,再减去最大时间得到时间差minDiff = Math.min(first + 1440 - last, minDiff);return minDiff;}
}
复杂度分析
假设时间列表的长度为n
时间复杂度
由于需要对时间进行排序,时间复杂度为O(nlogn),排序之后遍历集合,比较两两相邻的时间差,时间复杂度为O(n),故总的时间复杂度为O(nlogn) + O(n) = O(nlogn)
空间复杂度
由于当时间列表长度大于1440时(存在至少两个相同的时间),返回的时间差为0,所有集合的长度不会大于1440,是常数,故空间复杂度为O(1)
题解3(哈希表)
上题时间主要花在排序上,那有什么办法天然的让时间排序好呢?
一天有24小时,即1440小时,我们可以用一个容量为1440的布尔型数组来表示一天的时间,即数组下标为0的位置对应时间00:00,下标为1的位置对应时间00:01,以此类推,下标为1439的位置对应23:59。
那么在时间列表中的时间就可以对应数组的下标,即如果数组中的下标等于时间列表的时间,我们就让此下标的值为true,自然而然就把时间 排序好了
因此只需在遍历时间列表过程中,算出当前时间的分钟数,分钟数对应数组下标,让此下标的值为true
最后只需遍历数组,找到下标的值为true的两个时间即为两个相邻的时间,然后算出时间差,比较时间差即可算出最小时间差
特别地,当时间列表的长度超过1440,这说明时间列表中最少有两个相同的时间,相同的时间我们按当天的时间处理,则时间差为0即为最小时间差
同样的,在遍历时间列表算出分钟数时,如果发现此分钟数的下标的值已经为true,则说明有两个时间相同,则我们认为最小时间差为0
特别地,如果时间列表的存在时间00:00,则有两种情况的可能,当天的00:00或第二天的00:00,而上面数组的下标0对应的时间00:00,我们默认是当天的时间,因此我们还需要把第二天的时间00:00也考虑进去
换句话说就是把时间列表的第一个时间加上1440变成第二天的时间,然后减去时间列表的最后一个时间得到时间差
代码实现
class Solution {public int findMinDifference(List<String> timePoints) {// 若时间列表大于1440,则至少存在两个相等的时间,可以认为时间差为0if (timePoints.size() > 1440) {return 0;}// 创建创建为1440的布尔数组存放一天的时间,模拟哈希表boolean[] minuteFlags = new boolean[1440];// 遍历时间列表,遍历过程中算出分钟数for (String timePoint : timePoints) {String[] split = timePoint.split(":");int minute = Integer.parseInt(split[0]) * 60 + Integer.parseInt(split[1]);// 判断分钟数(下标)的值是否为true,若为true,则说明有两个相同的时间,返回0if (minuteFlags[minute]) {return 0;}// 令此分钟数(下标的值)为trueminuteFlags[minute] = true;}return helper(minuteFlags);}private int helper(boolean[] minuteFlags) {// 记录最小时间差,初始为最大值int minDiff = minuteFlags.length -1;// 存放遍历数组过程中的当前时间的前一个时间int pre = -1;// 存放最小时间,即数组第一个下标为true的时间int first = minuteFlags.length - 1;// 存放最大时间,即数组最后一个下标为true的时间int last = -1;// 遍历数组for (int i = 0; i < minuteFlags.length; i++) {// 若下标值为true,则执行下面逻辑,否则执行下一此循环if (minuteFlags[i]) {// 由于第一次循环时,当前时间没有前一个时间,则pre小于0,不执行此逻辑if (pre >= 0) {// 若当前时间等于当前时间的前一个时间,则两个时间相等,最小时间差为0if (i == pre) {return 0;}// 当前时间减去当前时间的前一个时间minDiff = Math.min(i - pre, minDiff);}// 重置当前时间的前一个时间,让当前时间的作为当前时间的下一个时间的前一个时间pre = i;// 记录最小时间,数组第一个下标为true的时间first = Math.min(i, first);// 记录最大时间,数组最后一个下标为true的时间last = Math.max(i, last);}}// 数组的第一个下标为true的时间加上24小时变成第二天的时间,然后减去当天的最晚时间minDiff = Math.min(first + minuteFlags.length - last, minDiff);return minDiff;}}
复杂度分析
假设时间列表的长度为n
时间复杂度
需要遍历时间列表把时间添加到数组中,时间复杂度为O(n),最后遍历数组算出两两相邻的时间,数组长度为1440,是常数,时间复杂度为O(1),故总的时间复杂度为O(n)
空间复杂度
数组的长度是固定的,故空间复杂度为O(1)
Java每日一题——>剑指 Offer II 035. 最小时间差(三解,蛮力,排序,哈希)相关推荐
- Leetcode刷题笔记——剑指offer II (五)【二分、排序、回溯】
这里写目录标题 二分查找 剑指 Offer II 069. 山峰数组的顶部 剑指 Offer II 070. 排序数组中只出现一次的数字 剑指 Offer II 071. 按权重生成随机数 剑指 Of ...
- java 栈和队列实现迷宫代码_LeetCode每日一题--剑指 Offer 09. 用两个栈实现队列(Java)
DailyChallenge 剑指 Offer 09. 用两个栈实现队列 Easy20200630 Description 用两个栈实现一个队列.队列的声明如下,请实现它的两个函数 appendTai ...
- 递增的整数序列链表的插入_每日算法题 | 剑指offer 链表专题 (5)链表中倒数第k个节点...
点击上方"Jerry的算法和NLP",选择"星标"公众号 重磅干货,第一时间送达 题目 链表中倒数第k个节点 题目要求 输入一个链表的头结点,从尾到头反过来打印 ...
- 力扣OJ 剑指 Offer II
目录 剑指 Offer II 001. 整数除法 剑指 Offer II 002. 二进制加法 剑指 Offer II 003. 前 n 个数字二进制中 1 的个数 剑指 Offer II 004. ...
- Leetcode刷题笔记——剑指offer II (六)【图】
文章目录 图 695. 岛屿的最大面积 剑指 Offer II 106. 二分图 (每条边的两个结点都来自不同的集合) 剑指 Offer II 107. 矩阵中的距离 (最短路问题,建图,BFS) 剑 ...
- leetcode每日一题--前缀树;前缀哈希;深搜;面试题 08.04. 幂集;648. 单词替换面试题 01.09. 字符串轮转;剑指 Offer II 062. 实现前缀树
leetcode每日一题 ps:今天的每日一题没意思,简单的模拟,自己换一道 面试题 08.04. 幂集 幂集.编写一种方法,返回某集合的所有子集.集合中不包含重复的元素. 说明:解集不能包含重复的子 ...
- 【算法leetcode每日一练】剑指 Offer II 080. 含有 k 个元素的组合 | 77. 组合
文章目录 剑指 Offer II 080. 含有 k 个元素的组合 | 77. 组合: 样例 1: 样例 2: 提示: 分析 题解 java c c++ python go rust javascri ...
- Leetcode刷题笔记——剑指offer II (一)【整数、数组、字符串、链表】
目录 整数 剑指 Offer II 001. 整数除法 剑指 Offer II 002. 二进制加法 剑指 Offer II 003. 前 n 个数字二进制中 1 的个数 剑指 Offer II 00 ...
- 剑指 Offer II 114. 外星文字典(困难 图 bfs 哈希表 拓扑排序 字符串 数组)
剑指 Offer II 114. 外星文字典 现有一种使用英语字母的外星文语言,这门语言的字母顺序与英语顺序不同. 给定一个字符串列表 words ,作为这门语言的词典,words 中的字符串已经 按 ...
最新文章
- 七十、反转和合并链表、 链表有环的判断
- python处理重复的复制粘贴_如何将数组复制/重复N次到新数组中?
- [ BZOJ 2160 ] 拉拉队排练
- JavaScript字符串方法终极指南-拆分
- 可穿戴在线展持续升温:聚焦产业热点 畅谈核心技术发展
- Conversion of Continuous-Valued Deep Networks to Efficient Event-Driven Networks for Image
- 网络分裂(network partition)
- 2020 美国大选在即,又到了 AI 花式打击假新闻的季节
- \045在字符串中输出为%
- 网站开发的需求分析报告
- 水位传感器工作原理及应用
- Linux fflush 函数
- 今年是嵌入式香还是互联网香?
- numpy matplotlib 进行图像读取和显示
- Linux/Unix获取时间戳
- 北邮计算机学院学生会军训,在北京邮电大学2015级本科生军训结训典礼上的讲话...
- h5与安卓交互 唤起手机照相、相册、摄影 视频播放 图片上传 录音 拨打电话
- Android 10 新增物理按键
- php外边框样式,CSS边框样式
- 软考高级系统架构设计师:论面向服务的架构及其应用