英文:
Issue with Time Calculation in Java
问题
以下是您要求的翻译内容:
在一个筛选测试中,我被要求编写一个程序,以获取一天中的最大空闲时间。
例如:
输入: "10:00AM-12:30PM","02:00PM-02:45PM","09:10AM-09:50AM"
期望的输出: 01:30
这些时间范围可能不是按递增顺序排列的。
针对这个问题,我尝试用Java写了一小段代码:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.time.Duration;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
public class TimeDiff {
public static void main(String[] args) throws NullPointerException {
String accStr = null;
System.out.println("输入白天的时间段:");
try (BufferedReader br = new BufferedReader(new InputStreamReader(System.in))) {
accStr = br.readLine();
} catch (IOException e) {
e.printStackTrace();
}
String unQuoted = accStr.replace("\"", "");
String[] inputSplit = unQuoted.split(",");
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("hh:mma");
Map<LocalTime, LocalTime> timeMap = new TreeMap<>();
for (String x : inputSplit) {
String[] furtherSplit = x.split("-");
timeMap.put(LocalTime.parse(furtherSplit[0], dateTimeFormatter), LocalTime.parse(furtherSplit[1], dateTimeFormatter));
}
Iterator iterator = timeMap.entrySet().iterator();
List<Long> duration = new ArrayList<Long>();
LocalTime[][] convertedMaptoArray = new LocalTime[timeMap.size()][2];
int rowIndex = 0;
while (iterator.hasNext()) {
int colIndex = 0;
Map.Entry pair = (Map.Entry) iterator.next();
//System.out.println(pair.getKey() + " " + pair.getValue());
convertedMaptoArray[rowIndex][colIndex] = (LocalTime) pair.getKey();
convertedMaptoArray[rowIndex][colIndex + 1] = (LocalTime) pair.getValue();
rowIndex++;
}
LocalTime previousRecordEndTime = null;
LocalTime currentRecordStartTime = null;
for (int i = 0; i <= convertedMaptoArray.length - 1; i++) {
currentRecordStartTime = convertedMaptoArray[i][0];
//System.out.println("current :" + currentRecordStartTime);
if (i > 0) {
previousRecordEndTime = convertedMaptoArray[i - 1][1];
//System.out.println("Previous : " + previousRecordEndTime);
duration.add(ChronoUnit.MINUTES.between(previousRecordEndTime, currentRecordStartTime));
}
}
System.out.println("最长持续时间:" + LocalTime.MIN.plus(Duration.ofMinutes(Collections.max(duration))).toString());
}
}
我被淘汰了,但我对上述代码有一些问题:
- 如何进一步优化这段代码?
- 以上代码是否违反了任何编码规则?
- 在Java中计算时间的更好方法是什么?
请帮忙解答。提前致谢。
英文:
In a screening test I've been asked to write a program to get the maximum free time available during a day.
For example :
>Input: "10:00AM-12:30PM","02:00PM-02:45PM","09:10AM-09:50AM"
<br>Expected Output: 01:30
These time ranges may not be in increasing order.
For this issue I've tried to write a small code in java as :
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.time.Duration;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
public class TimeDiff {
public static void main(String[] args) throws NullPointerException {
String accStr = null;
System.out.println("Enter day time entries : ");
try (BufferedReader br = new BufferedReader(new InputStreamReader(System.in))) {
accStr = br.readLine();
} catch (IOException e) {
e.printStackTrace();
}
String unQuoted = accStr.replace("\"", "");
String[] inputSplit = unQuoted.split(",");
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("hh:mma");
Map<LocalTime, LocalTime> timeMap = new TreeMap<>();
for (String x : inputSplit) {
String[] furtherSplit = x.split("-");
timeMap.put(LocalTime.parse(furtherSplit[0], dateTimeFormatter), LocalTime.parse(furtherSplit[1], dateTimeFormatter));
}
Iterator iterator = timeMap.entrySet().iterator();
List<Long> duration = new ArrayList<Long>();
LocalTime[][] convertedMaptoArray = new LocalTime[timeMap.size()][2];
int rowIndex = 0;
while (iterator.hasNext()) {
int colIndex = 0;
Map.Entry pair = (Map.Entry) iterator.next();
//System.out.println(pair.getKey() + " " + pair.getValue());
convertedMaptoArray[rowIndex][colIndex] = (LocalTime) pair.getKey();
convertedMaptoArray[rowIndex][colIndex+1]=(LocalTime)pair.getValue();
rowIndex++;
}
LocalTime previousRecordEndTime = null;
LocalTime currentRecordStartTime = null;
for(int i= 0; i<=convertedMaptoArray.length-1;i++)
{
currentRecordStartTime = convertedMaptoArray[i][0];
//System.out.println("current :" +currentRecordStartTime);
if(i>0){
previousRecordEndTime = convertedMaptoArray[i-1][1];
//System.out.println("Previous : " + previousRecordEndTime);
duration.add(ChronoUnit.MINUTES.between(previousRecordEndTime, currentRecordStartTime));
}
}
System.out.println("Longest duration : " + LocalTime.MIN.plus(Duration.ofMinutes(Collections.max(duration))).toString());
}
}
I was screened out but I've few questions regarding above code :
- How this code can be optimized more?
- Is there any coding rule which above code is breaking?
- What should be better approach to calculate time in Java?
Please help. Thanks in advance.
答案1
得分: 3
我会争辩说你正在违反 KISS 原则(过度复杂化事物),同时混合了两个非常不同的职责:解析输入和计算时间间隔 - 你只关心最短的间隔,所以不需要存储所有内容。
输入是否假定为通过控制台输入的字符串?
我已将其拆分为以下方法:
// 01:00AM -> 60
private static int timeStringToMinutesFromMidnight(String time)
// 60 -> 01:00
private static String minutesToHoursAndMinutes(int minutes)
// 11:00AM-11:30AM -> 660 690 加入列表
private static void parseInterval(String interval, List<Integer> minutes)
(在之前的编辑中,我有timeStringIntervalToMinutes
,但我误读了问题,并计算了错误的输出)。
在这里你不需要任何复杂的数据结构:一个简单的List
就足以完成所有所需的操作。对它进行排序比使用TreeMap
或TreeSet
更容易 - 是的,它们会自行排序,但在占用空间和访问速度方面也更重。
完整代码(导入java.util.*
和java.io.*
):
// 01:00AM -> 60
private static int timeStringToMinutesFromMidnight(String time) {
// ...
}
// 60 -> 01:00
private static String minutesToHoursAndMinutes(int minutes) {
// ...
}
// 11:00AM-11:30AM -> 660 690 加入列表
private static void parseInterval(String interval, List<Integer> minutes) {
// ...
}
// 输入: "10:00AM-12:30PM","02:00PM-02:45PM","09:10AM-09:50AM"
// 预期输出: 01:30
public static void main(String ... args) {
// ...
}
英文:
I would argue that you are breaking KISS (overcomplicating things) and, at the same time, mixing 2 very different responsibilities: that of parsing the input, and that of calculating intervals - of which you are only interested in the shortest, so storing everything is not necessary.
Is the input assumed to be a string entered through the console?
I have broken it up into the following methods:
// 01:00AM -> 60
private static int timeStringToMinutesFromMidnight(String time)
// 60 -> 01:00
private static String minutesToHoursAndMinutes(int minutes)
// 11:00AM-11:30AM -> 660 690 added to list
private static void parseInterval(String interval, List<Integer> minutes)
(in a previous edit, I had timeStringIntervalToMinutes
, but I had misread the question and was calculating the wrong output).
You do not need any complicated data-structure here: a simple List
allows you to do everything required. Sorting it is easier than working with a TreeMap
or a TreeSet
- yes, they do their own sorting, but are also much heavier in terms of footprint and access speed.
Complete code (imports java.util.*
and java.io.*
):
// 01:00AM -> 60
private static int timeStringToMinutesFromMidnight(String time) {
int hours = Integer.parseInt(time.substring(0,"hh".length()));
int minutes = Integer.parseInt(time.substring("hh:".length(), "hh:mm".length()));
boolean afternoon = time.substring("hh:mm".length()).equalsIgnoreCase("PM");
if (afternoon && hours != 12) {
hours += 12;
}
return hours * 60 + minutes;
}
// 60 -> 01:00
private static String minutesToHoursAndMinutes(int minutes) {
int hours = minutes / 60;
minutes = minutes % 60;
return String.format("%02d:%02d", hours, minutes);
}
// 11:00AM-11:30AM -> 660 690 added to list
private static void parseInterval(String interval, List<Integer> minutes) {
String[] parts = interval.split("-");
int start = timeStringToMinutesFromMidnight(parts[0]);
int end = timeStringToMinutesFromMidnight(parts[1]);
if (end < start) {
throw new IllegalArgumentException("interval " + interval + " has end<start");
}
minutes.add(start);
minutes.add(end);
}
// Input: "10:00AM-12:30PM","02:00PM-02:45PM","09:10AM-09:50AM"
// Expected Output: 01:30
public static void main(String ... args) {
List<Integer> endpoints = new ArrayList<>();
try (Scanner sc = new Scanner(System.in).useDelimiter("[,\"]+")) {
while (sc.hasNext()) {
parseInterval(sc.next(), endpoints);
}
}
if (endpoints.isEmpty()) {
System.out.println("No intervals found");
return;
}
// sort the endpoints (assuming that no intervals overlap, intervals will not be broken)
Collections.sort(endpoints);
int largest = -1;
for (int i=1; i<endpoints.size()-1; i+=2) {
largest = Math.max(largest, endpoints.get(i+1) - endpoints.get(i));
}
System.out.println(minutesToHoursAndMinutes(largest));
}
答案2
得分: 2
我建议:
- 不要使用
Map
存储条目。可以使用一个 pair 类,或者定义一个TimeRange
类,可以保存两个LocalTime
对象。然后创建一个包含这些对象的集合。 - 即使你想要使用
Map
,也不要使用原始的Map.Entry
。将其参数化为Map.Entry<LocalTime, LocalTime>
。类似地,将迭代器参数化。另一方面,new ArrayList<Long>()
中的类型参数是多余的;只需使用new ArrayList<>()
即可。 - 不要使用
Long
表示持续时间。直接在整个过程中使用Duration
类。可以使用它的compareTo
方法进行比较。 - 我建议先将字符串拆分为时间范围,然后仅去掉开头和结尾的引号。这可以提供一定程度的输入验证。
- 要找到最大的空闲持续时间,可以使用内置的最大值方法,例如双参数的
Collections.max()
。可以传递从Arrays.asList()
获取的列表,或者更好的是,避免使用数组,将持续时间仅保存在列表中。然后当然需要一个适当的Comparator
实现。
英文:
I suggest:
- Don’t use a
Map
for your entries. Use a pair class or define aTimeRange
class that can hold twoLocalTime
objects. And then make a collection of those. - Even if you want to use a
Map
, don’t use a rawMap.Entry
. Parameterize asMap.Entry<LocalTIme, LocalTime>
. Similarly parameterize your iterator. (On the other hand the type parameter innew ArrayList<Long>()
is redundant; justnew ArrayList<>()
would be conventional.) - Don’t use
Long
for durations. Just use theDuration
class throughout. Use itscompareTo
method for comparison. - I’d split the string into time ranges first and then remove only leading and trailing quotes. This gives a degree of input validation.
- For finding the max free duration I would use a built-in max method, for example the two-arg
Collections.max()
. I’d pass a list obtained fromArrays.asList()
, or even better, avoid arrays and keep the durations in a list exclusively. And then of course an appropriateComparator
implementation.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论