zoukankan      html  css  js  c++  java
  • [LeetCode 920] Number of Music Playlists

    Your music player contains N different songs and she wants to listen to L (not necessarily different) songs during your trip.  You create a playlist so that:

    • Every song is played at least once
    • A song can only be played again only if K other songs have been played

    Return the number of possible playlists.  As the answer can be very large, return it modulo 10^9 + 7.

    Example 1:

    Input: N = 3, L = 3, K = 1
    Output: 6
    Explanation: There are 6 possible playlists. [1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1].
    

    Example 2:

    Input: N = 2, L = 3, K = 0
    Output: 6
    Explanation: There are 6 possible playlists. [1, 1, 2], [1, 2, 1], [2, 1, 1], [2, 2, 1], [2, 1, 2], [1, 2, 2]
    

    Example 3:

    Input: N = 2, L = 3, K = 1
    Output: 2
    Explanation: There are 2 possible playlists. [1, 2, 1], [2, 1, 2]
    

    Note:

    1. 0 <= K < N <= L <= 100

    A brute force solution is to check all possible permutations and add those that meet the given requirements to the final count. The runtime is O(L!) * O(L), which is infeasible for a input size up to 100. The following table can be used to guess the required time complexity of the algorithm that solves a problem, assuming a time limit of one second.

    Input size  required time complexity
    n <= 10 O(n !)
    n <= 20 O(2 ^ n)
    n <= 500 O(n ^ 3)
    n <= 5000 O(n ^ 2)
    n <= 10^6 O(nlogn) or O(n)
    n is large O(1) or O(logn)
      

    Anyway, back to business.  If we consider only one song's choice at a time, we can solve this problem recursively. For the last picked song, there can only be two cases. Either it is not picked before or it has been picked before. 

    The recursive formula is as following. If the last song is never picked before, the original problem F(N, L, K) is reduced to F(N - 1, L - 1, K) and we have N songs to choose from. Or the last song has been picked before, the original problem is reduced to F(N, L - 1, K) and we have N - K songs to choose from.(This satisfies the K buffer requirement)

    F(N, L, K) = F(N - 1, L - 1) * N + F(N, L - 1, K) * (N - K)

    There are two base cases:

    1. N == K + 1, this means the number of available songs just meet the buffer requirement. There are N ! permutations and for every permutation, the rest of song choices is fixed since any other ordering breaks the buffering rule.

    2. N == L, since each song must be picked at least once,  there are N ! possible orderings.

    The recursion tree reveals that there will be a lot of redundant recursive computations. For instance, F(N - 1, L - 2) will be computed twice. This is an indication of dynamic programming. A good trick of computing factorials is to use a 1D arrray to store all factorials. This avoids redundant computations as well.

    Both dp solutions have a runtime of O((N - K) * (L - K)) and space of O(N * L).

    Top down recursion with memoization 

    class Solution {  
        private int mod = (int)1e9 + 7;
        private long[] factorial;
        private long[][] dp;
        public int numMusicPlaylists(int N, int L, int K) {     
            factorial = new long[N + 1];
            dp = new long[N + 1][L + 1];
            factorial[0] = 1;
            for(int i = 1; i <= N; i++) {
                factorial[i] = factorial[i - 1] * i % mod;
            }
                  
            return (int)recursionWithMemo(N, L, K);
        }
        private long recursionWithMemo(int n, int l, int k) {
            if(dp[n][l] == 0) {
                if(n == l || n == k + 1) {
                    dp[n][l] = factorial[n];
                }
                else {
                    dp[n][l] = (recursionWithMemo(n - 1, l - 1, k) * n + recursionWithMemo(n, l - 1, k) * (n - k)) % mod;
                }
            }
            return dp[n][l];
        }
    }

    Bottom up DP

    class Solution {
        public int numMusicPlaylists(int N, int L, int K) {
            int mod = (int)1e9 + 7;
            long[] factorial = new long[N + 1];
            factorial[0] = 1;
            for(int i = 1; i <= N; i++) {
                factorial[i] = factorial[i - 1] * i % mod;
            }
            long[][] dp = new long[N + 1][L + 1];
            for(int i = K + 1; i <= N; i++) {
                for(int j = i; j <= L; j++) {
                    if(i == j || i == K + 1) {
                        dp[i][j] = factorial[i];
                    }
                    else {
                        dp[i][j] = (dp[i - 1][j - 1] * i + dp[i][j - 1] * (i - K)) % mod;
                    }
                }
            }
            return (int)dp[N][L];
        }
    }
  • 相关阅读:
    ASP.NET Core2利用MassTransit集成RabbitMQ
    ASP.NET Core2集成Office Online Server(OWAS)实现办公文档的在线预览与编辑(支持wordexcelpptpdf等格式)
    ASP.NET Core2利用Jwt技术在服务端实现对客户端的身份认证
    net core System.Drawing is not supported on this platform.
    小程序开发之维护access_token
    net core 100个案例
    msgSystem.Drawing is not supported on this platform【netcore】
    wpf,前端动画demo,鱼眼效果
    自定义控件,重写 TextBox 实例
    TextBox输入法控制,进入输入框则启用或禁用输入法(ime),禁用后只能输入英文
  • 原文地址:https://www.cnblogs.com/lz87/p/11651570.html
Copyright © 2011-2022 走看看