LeetCode 1010. 总持续时间可被 60 整除的歌曲(Hash+递推)

54 篇文章 0 订阅

1.题目

在歌曲列表中,第 i 首歌曲的持续时间为 time[i] 秒。
返回其总持续时间(以秒为单位)可被 60 整除的歌曲对的数量。形式上,我们希望索引的数字 i 和 j 满足 i < j 且有 (time[i] + time[j]) % 60 == 0。

示例 1:

输入:[30,20,150,100,40]
输出:3
解释:这三对的总持续时间可被 60 整数:
(time[0] = 30, time[2] = 150): 总持续时间 180
(time[1] = 20, time[3] = 100): 总持续时间 120
(time[1] = 20, time[4] = 40): 总持续时间 60
示例 2:

输入:[60,60,60]
输出:3
解释:所有三对的总持续时间都是 120,可以被 60 整数。
 

提示:

1 <= time.length <= 60000
1 <= time[i] <= 500

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/pairs-of-songs-with-total-durations-divisible-by-60
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

2题解

一次遍历+递推:

实际我们可以把余数桶认为是一个等待配对的“登记表”,每一次得到一个时间值我们都按照如下操作进行处理:

假设之前的“登记表”上的已有的配对都已经被正确处理了,待处理的只有这个新的时间值
检查“登记表”中是否有需要它进行配对的值,有多少个就又增加了多少个配对
本次配对完成,把当前时间值登记入表,等待后面的时间和它进行配对
本解法当然不会分别记录每个新加入的时间对应的配对数量,但是每次处理新的时间会更新结果计数,实际就是递推状态的记录,实际仍然隐含了递推的想法。只要确定了最初没有处理时间时的配对数量作初始值,即可开始从头递推,显然初始值是 0。

这样,利用动态增长的“登记表”就能只使用一次遍历,并且规避了解法一中的二次计数问题,而且也不需要对余数 30 的情况进行特殊处理。

class Solution
{
public:
    int numPairsDivisibleBy60(vector<int>& time)
    {
        int res = 0;
        vector<int> ans(60);
        for(int num : time)
        {
            int mod = num % 60;
            int target = mod == 0 ? 0 : 60 - mod;
            res += ans[target];						//找满足条件的target的次数
            ans[mod]++;								
        }
        return res;
    }
};

链接:https://leetcode-cn.com/problems/pairs-of-songs-with-total-durations-divisible-by-60/solution/jian-duan-you-rong-yi-li-jie-de-on-suan-fa-by-ciel/

两次遍历:
class Solution
{
public:
    //2次遍历
    int numPairsDivisibleBy60(vector<int>& time)
    {
        int rs = 0;
        vector<int>hash(60); //0-59
        for (int num : time)
        {
            hash[num%60]++;
        }
        //20 30 40
        //1  2  2
        for (int num : time)
        {
            //遍历到一个数字 就让他-1,因为已经被用过了  比如20和40匹配   后面避免40和20匹配
            int mod = num % 60;
            hash[mod]--;
            int target = mod == 0 ? 0 : 60 - mod;
            rs += hash[target];
        }
        return rs;
    }
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值