版权声明:本文为博主原创文章,未经博主允许不得转载。有事联系:[email protected] https://blog.csdn.net/qq_17550379/article/details/82992083
你的音乐播放器里有 N
首不同的歌,在旅途中,你的旅伴想要听 L
首歌(不一定不同,即,允许歌曲重复)。请你为她按如下规则创建一个播放列表:
- 每首歌至少播放一次。
- 一首歌只有在其他
K
首歌播放完之后才能再次播放。
返回可以满足要求的播放列表的数量。由于答案可能非常大,请返回它模 10^9 + 7 的结果。
示例 1:
输入:N = 3, L = 3, K = 1
输出:6
解释:有 6 种可能的播放列表。[1, 2, 3],[1, 3, 2],[2, 1, 3],[2, 3, 1],[3, 1, 2],[3, 2, 1].
示例 2:
输入:N = 2, L = 3, K = 0
输出:6
解释:有 6 种可能的播放列表。[1, 1, 2],[1, 2, 1],[2, 1, 1],[2, 2, 1],[2, 1, 2],[1, 2, 2]
示例 3:
输入:N = 2, L = 3, K = 1
输出:2
解释:有 2 种可能的播放列表。[1, 2, 1],[2, 1, 2]
提示:
0 <= K < N <= L <= 100
解题思路
大家首先应该可以想到的解法就是将所以的集合都找出来,然后对这些集合中相同元素的位置比较,如果位置<k
,那么就剔除,最后剩下的就是我们需要的解。这种暴力解法思路很简单,但是实际操作起来并不容易,而且速度也很慢。
这个问题可以通过动态规划的方法解决。我们定义函数f(n,l,k)
表示n
首歌填充l
个位置,相同歌的间隔超过k
。那么,我们对于第l
个位置来说只有两种情况
- 之前没有相同的歌,也就是说
n-1
首歌填充了前面l-1
个位置,即f(n-1,l-1,k)
- 之前有相同的歌,也就是说
n
首歌填充了前面l-1
个位置,即f(n,l-1,k)
对于第一种情况,因为有n
首歌,所以会出现n
次。而对于第二种情况,由于相同的歌不能间隔k
,所以会出现n-k
次,那么
f(n,l,k)=f(n-1,l-1,k)*n+f(n,l-1,k)*(n-k)
接着我们考虑边界条件:当n==l
时,即为全排列,也就是n!
种;当i<=K
的时候,解不存在,很好理解;当n==K+1
时,也是全排列,因为此时最后一首歌会和第一首歌相同。
扫描二维码关注公众号,回复:
3543735 查看本文章
class Solution:
def numMusicPlaylists(self, N, L, K):
"""
:type N: int
:type L: int
:type K: int
:rtype: int
"""
mem = [[0]*(L+1) for _ in range(N+1)]
for i in range(K+1, N+1):
for j in range(i, L + 1):
if i == j or i == K + 1:
mem[i][j] = math.factorial(i)
else:
mem[i][j] = mem[i-1][j-1]*i + mem[i][j-1]*(i - K)
return mem[N][L]%(10**9 + 7)
reference:
https://leetcode.com/problems/number-of-music-playlists/discuss/178415/C++JavaPython-DP-Solution
我将该问题的其他语言版本添加到了我的GitHub Leetcode
如有问题,希望大家指出!!!