簡體   English   中英

Java 中的時間計算問題

[英]Issue with Time Calculation in Java

在篩選測試中,我被要求編寫一個程序來獲得一天中可用的最大空閑時間。

例如:

輸入: “10:00AM-12:30PM”,“02:00PM-02:45PM”,“09:10AM-09:50AM”
預計 Output: 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("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());

    }
}

我被篩選了,但我對上面的代碼有幾個問題:

  1. 如何優化這段代碼?
  2. 上面的代碼是否違反了任何編碼規則?
  3. 在 Java 中計算時間應該有什么更好的方法?

請幫忙。 提前致謝。

我認為你正在破壞 KISS(使事情過於復雜),同時混合了 2 個截然不同的職責:解析輸入的職責和計算間隔的職責 - 你只對最短的時間感興趣,因此存儲所有內容沒有必要。

輸入是否假定為通過控制台輸入的字符串?

我將其分解為以下方法:

// 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)

(在之前的編輯中,我有timeStringIntervalToMinutes ,但我誤讀了問題並且計算了錯誤的輸出)。

您在這里不需要任何復雜的數據結構:一個簡單的List可以讓您完成所需的一切。 對其進行排序比使用TreeMapTreeSet更容易 - 是的,它們進行自己的排序,但在占用空間和訪問速度方面也更重。

完整代碼(導入java.util.*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));
}

我建議:

  • 不要將Map用於您的條目。 使用一對 class 或定義一個TimeRange class 可以容納兩個LocalTime對象。 然后收集這些。
  • 即使你想使用Map ,也不要使用原始的Map.Entry 參數化為Map.Entry<LocalTIme, LocalTime> 同樣參數化你的迭代器。 (另一方面, new ArrayList<Long>()中的類型參數是多余的;只是new ArrayList<>()是常規的。)
  • 不要將Long用於持續時間。 只需在整個過程中使用Duration class。 使用其compareTo方法進行比較。
  • 我首先將字符串拆分為時間范圍,然后僅刪除前導引號和尾隨引號。 這提供了一定程度的輸入驗證。
  • 為了找到最大免費持續時間,我會使用內置的 max 方法,例如雙參數Collections.max() 我會傳遞從Arrays.asList()獲得的列表,或者甚至更好,避免 arrays 並將持續時間專門保留在列表中。 然后當然是適當的Comparator實現。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM