[LeetCode] 1010. Pairs of Songs With Total Durations Divisible by 60 總持續時間可被60整除的歌曲



You are given a list of songs where the ith song has a duration of time[i] seconds.

Return the number of pairs of songs for which their total duration in seconds is divisible by 60. Formally, we want the number of indices ij such that i < j with (time[i] + time[j]) % 60 == 0.

Example 1:

Input: time = [30,20,150,100,40]
Output: 3
Explanation: Three pairs have a total duration divisible by 60:
(time[0] = 30, time[2] = 150): total duration 180
(time[1] = 20, time[3] = 100): total duration 120
(time[1] = 20, time[4] = 40): total duration 60

Example 2:

Input: time = [60,60,60]
Output: 3
Explanation: All three pairs have a total duration of 120, which is divisible by 60.

Constraints:

  • 1 <= time.length <= 6 * 104
  • 1 <= time[i] <= 500

這道題說是給了一個歌曲列表的每首歌的播放時長,現在讓找出有多少對兒的歌曲,使得其播放時長之和是 60 的倍數,看到這里有沒有覺得很眼熟,沒錯,其實本質還是一道 Two Sum 的題,來跟着博主一起大聲念 ’平生不識 TwoSum,刷盡 LeetCode 也枉然‘。不過這里不是簡單的判斷兩數之和是否存在,而是要求出所有的符合題意的個數。由於數組中可能出現重復數字,所以需要統計出每個數字出現的個數。另外,這道題有一個很好的 trick,利用到了余數的性質,若兩個數之和可以被 60 整數,則對其先分別對 60 取余后,再相加之和,還是可以被 60 整數,這樣就可以把數字都縮小到 [0, 59] 的范圍內了。之后就是要找和可以被 60 整除的兩個數字了,經典的 Two Sum 的思路是先確定一個數字,然后用目標和減去當前這個數字,就是要在 HashMap 中查找是否存在。若是兩個數字不同,則總共的組合數就是兩個數字的出現次數直接相乘,但是假如兩個數字相同,則是個組合問題,比如在n個數字中任意選兩個數字的情況有多少種,為 n(n - 1) / 2。這里兩個數字相同有兩種情況,一種是它們都是 60 的倍數,取余后都變成了0,另一種是它們都是 30,這樣加起來就是 60 的倍數,這兩種情況要單獨計算。還有,就是要用一個 HashSet 記錄已經處理過的數字,以免產生重復計算,參見代碼如下:


解法一:

class Solution {
public:
    int numPairsDivisibleBy60(vector<int>& time) {
        int res = 0;
        unordered_set<int> visited;
        unordered_map<int, int> timeCnt;
        for (int t : time) ++timeCnt[t % 60];
        for (auto &a : timeCnt) {
            if (visited.count(a.first)) continue;
            if (a.first % 60 == 0 || a.first == 30) {
                res += (a.second - 1) * a.second / 2;
            } else {
                int target = 60 - a.first;
                if (!timeCnt.count(target)) continue;
                res += a.second * timeCnt[target];
                visited.insert(target);
            }
            visited.insert(a.first);
        }
        return res;
    }
};

其實有種更簡潔的寫法,不用在統計完了出現次數之后再計算,而是在統計的時候就直接累加了。這里沒有用 HashMap,而是直接用了一個大小為 60 的數組,上面提到了通過對 60 取余,可以把數字都縮小到 [0, 59] 的范圍內,對於每次遍歷到的數字,加上能和其配對的數字的出現次數,方法是用 600 減去當前數字,然后對 60 取余。然后累加對 60 取余的次數,參見代碼如下:


解法二:

class Solution {
public:
    int numPairsDivisibleBy60(vector<int>& time) {
        int res = 0;
        vector<int> cnt(60);
        for (int t : time) {
            res += cnt[(600 - t) % 60];
            ++cnt[t % 60];
        }
        return res;
    }
};

Github 同步地址:

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


類似題目:

Two Sum


參考資料:

https://leetcode.com/problems/pairs-of-songs-with-total-durations-divisible-by-60/

https://leetcode.com/problems/pairs-of-songs-with-total-durations-divisible-by-60/discuss/256738/JavaC%2B%2BPython-Two-Sum-with-K-60

https://leetcode.com/problems/pairs-of-songs-with-total-durations-divisible-by-60/discuss/256726/JavaPython-3-O(n)-code-w-comment-similar-to-Two-Sum


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


免責聲明!

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



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