[LeetCode] 949. Largest Time for Given Digits 由給定數字組成的最大時間



Given an array of 4 digits, return the largest 24 hour time that can be made.

The smallest 24 hour time is 00:00, and the largest is 23:59.  Starting from 00:00, a time is larger if more time has elapsed since midnight.

Return the answer as a string of length 5.  If no valid time can be made, return an empty string.

Example 1:

Input: [1,2,3,4]
Output: "23:41"

Example 2:

Input: [5,5,5,5]
Output: ""

Note:

  1. A.length == 4
  2. 0 <= A[i] <= 9

這道題給了我們四個數字,讓組成 24 小時制能表示的最大時間,並且數字可以重復。注意並不是任意給四個數字都能組成時間,因為小時的第一個數字只能是 0,1,2 三個數字,並且若第一個數字是2,第二個數字只能是 0,1,2,3 這四個數。且分鍾的第一個數字必須小於6,這些都是表示時間的一些規則,畢竟一天只有 24 個小時,一個小時只有 60 分鍾。最簡單暴力的方法就是遍歷所有的排列情況,然后去驗證當前順序是否可以正確的表示 24 小時制的時間。想偷懶的話可以使用 STL 內置的 next_permutation 方法來快速返回下一個排列,但是注意要先給數組排個序,使數組變為升序的,不然若直接給個降序數組,該函數沒法返回下一個排列。給數組排序還有個好處就是讓小的數字到前面,因為表示小時的數字比較小。得到一個排列后,看組成小時的兩個數字是否小於等於 23,且表示分鍾的兩個數字是否小於等於 59,若都滿足的話,則更新結果 res 為當前的排列即可,參見代碼如下:


解法一:

class Solution {
public:
    string largestTimeFromDigits(vector<int>& A) {
        string res;
        sort(A.begin(), A.end());
        do {
            string hour = {char(A[0] + '0'), char(A[1] + '0')}, minute = {char(A[2] + '0'), char(A[3] + '0')};
            res = (hour <= "23" && minute <= "59") ? (hour + ":" + minute) : res;
        } while(next_permutation(A.begin(), A.end()));
        return res;
    }
};

你可能不屑於用 STL 內置函數來做,覺得簡直是在耍賴,不能忍。那么下面就用一般的寫法吧,反正只有四個數字,使用三個 for 循環就搞定了,分別用 i,j,k,6-i-j-k,來表示某個排列四個數字在原數組中的坐標,得到了排列順序后,就可以分別組成小時和分鍾的字符串表示了,但是需要注意的時候,由於此時是無序的,所以更新結果 res 的時候,要多加一個條件,當新的排序時間大於 res 時,才能更新,參見代碼如下:


解法二:

class Solution {
public:
    string largestTimeFromDigits(vector<int>& A) {
        string res;
        for (int i = 0; i < 4; ++i) {
            for (int j = 0; j < 4; ++j) {
                for (int k = 0; k < 4; ++k) {
                    if (i == j || i == k || j == k) continue;
                    string hour = {char(A[i] + '0'), char(A[j] + '0')}, minute = {char(A[k] + '0'), char(A[6 - i - j - k] + '0')}, t = hour + ":" + minute;
                    if (hour <= "23" && minute <= "59" && res < t) res = t;
                }
            }
        }
        return res;
    }
};

之前的方法都是各種搗鼓數組A,下面來看一種遍歷所有時間組合的解法。因為小時只有 24 個數組,分鍾只有 60 個數字,可以用兩個 for 循環遍歷所有的時間組合,然后反向去驗證這四個數字是否和A中的數字相同,為了快速驗證,使用一個數組來記錄每個數字的出現次數。由於小時和分鍾都是兩位數,只能用除以 10 或者對 10 取余來分別取出十位和個位上的數字。這里可以進行一個小優化,因為小於 10 的話,十位上的數字就是0,可以省去除法操作。等統計好了數字后,遍歷數組A,每次減去對應位置的數字,當次數變成負數的時候,說明A中沒有足夠的該數字,使用一個布爾型變量來標記當前排列不行,並 break 掉。若某個排列可以由A組成的話,就要開始拼接時間字符串,如果是 Java 的話,那就非常的簡單方便了,直接用 String.format("%02d:%02d", h, m) 就可以了,但是 C++ 比較麻煩,還得手動判斷並加首位0,這簡直就是把人往 Java 陣營推啊,參見代碼如下:


解法三:

class Solution {
public:
    string largestTimeFromDigits(vector<int>& A) {
        for (int h = 23; h >= 0; --h) {
            for (int m = 59; m >= 0; --m) {
                vector<int> cnt(10);
                bool valid = true;
                ++cnt[h < 10 ? 0 : h / 10];
                ++cnt[h < 10 ? h : h % 10];
                ++cnt[m < 10 ? 0 : m / 10];
                ++cnt[m < 10 ? m : m % 10];
                for (int num : A) {
                    if (--cnt[num] < 0) {
                        valid = false;
                        break;
                    }
                }
                string hour = to_string(h), minute = to_string(m);
                if (valid) return (h < 10 ? "0" + hour : hour) + ":" + (m < 10 ? "0" + minute : minute);
            }
        }
        return "";
    }
};

Github 同步地址:

https://github.com/grandyang/leetcode/issues/949


參考資料:

https://leetcode.com/problems/largest-time-for-given-digits/submissions/

https://leetcode.com/problems/largest-time-for-given-digits/discuss/207126/Elegant-C%2B%2B-solution!)

https://leetcode.com/problems/largest-time-for-given-digits/discuss/202234/Java-Super-Short-Solution-!!!

https://leetcode.com/problems/largest-time-for-given-digits/discuss/200693/JavaPython-3-11-liner-O(64)-w-comment-6-ms.


LeetCode All in One 題目講解匯總(持續更新中...)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM