返回
**LeetCode 1418. 点歌时间 总持续时间可被 60 整除的歌曲**
前端
2024-02-03 08:45:28
引言
音乐播放列表中有一系列歌曲,这些歌曲的持续时间以秒为单位给出。现在,需要从播放列表中选择一些歌曲,使得它们的总持续时间恰好可以被 60 整除。换句话说,就是要求所选歌曲的总持续时间是 60 的倍数。
解题思路
1. 模拟
我们可以使用模拟法逐一尝试从播放列表中选择歌曲。对于每首歌,我们都可以将其持续时间添加到当前已选择的歌曲的总持续时间中。如果添加后总持续时间可以被 60 整除,那么我们就找到了一个可行解。
2. 公式
更优化的解法是利用数学公式。假设播放列表中有 n 首歌曲,它们的持续时间分别为 t1、t2、...、tn。那么,要使总持续时间恰好可以被 60 整除,等价于:
t1 + t2 + ... + tn ≡ 0 (mod 60)
其中,≡ 表示同余运算。
基于这个公式,我们可以使用动态规划的方法解决这个问题。具体步骤如下:
步骤 1:初始化
创建一个二维数组 dp,其中 dp[i][j] 表示考虑前 i 首歌曲,并且剩余时间为 j 时,能否找到一个可行解。
步骤 2:状态转移
对于第 i 首歌曲,有两种选择:
- 不选择第 i 首歌曲:dp[i][j] = dp[i - 1][j]
- 选择第 i 首歌曲:dp[i][j] = dp[i - 1][j - t[i]]
步骤 3:边界条件
当 j 为 0 时,表示已经找到了一个可行解,因此 dp[i][0] = true。
步骤 4:结果
最后,检查 dp[n][0] 是否为 true。如果是,则存在可行解;否则,不存在可行解。
代码实现
JavaScript
const canChooseSongs = (time) => {
// 剩余时间范围
const MOD = 60;
const n = time.length;
// 初始化 dp 数组
const dp = Array(n + 1).fill(null).map(() => Array(MOD + 1).fill(false));
dp[0][0] = true;
// 状态转移
for (let i = 1; i <= n; i++) {
for (let j = 0; j <= MOD; j++) {
dp[i][j] = dp[i - 1][j];
if (j >= time[i - 1]) {
dp[i][j] |= dp[i - 1][j - time[i - 1]];
}
}
}
return dp[n][0];
};
时间复杂度 :O(n * MOD)
空间复杂度 :O(n * MOD)
总结
通过模拟和公式相结合的方法,我们能够高效地解决 LeetCode 1418 题「点歌时间」的问题。该解法不仅清晰易懂,而且可以很好地扩展到类似的问题中。