• [LeetCode] 1866. Number of Ways to Rearrange Sticks With K Sticks Visible Review


    There are n uniquely-sized sticks whose lengths are integers from 1 to n. You want to arrange the sticks such that exactly k sticks are visible from the left. A stick is visible from the left if there are no longer sticks to the left of it.

    • For example, if the sticks are arranged [1,3,2,5,4], then the sticks with lengths 13, and 5 are visible from the left.

    Given n and k, return the number of such arrangements. Since the answer may be large, return it modulo 109 + 7.

     

    Example 1:

    Input: n = 3, k = 2
    Output: 3
    Explanation: [1,3,2], [2,3,1], and [2,1,3] are the only arrangements such that exactly 2 sticks are visible.
    The visible sticks are underlined.
    

    Example 2:

    Input: n = 5, k = 5
    Output: 1
    Explanation: [1,2,3,4,5] is the only arrangement such that all 5 sticks are visible.
    The visible sticks are underlined.
    

    Example 3:

    Input: n = 20, k = 11
    Output: 647427950
    Explanation: There are 647427950 (mod 109 + 7) ways to rearrange the sticks such that exactly 11 sticks are visible.
    

     

    Constraints:

    • 1 <= n <= 1000
    • 1 <= k <= n

    If using the commented out logic, the runtime will be O(N^3) instead of O(N^2). The key observation here is that if we try to arrange sticks from the right side, out of all the available sticks to choose from, the tallest one is always visible, it also always blocks all the shorter sticks to its right. So if we are given a subproblem of having n sticks to choose from and wanting to get k visible sticks, we either put the tallest on the right most position, which reduce to subproblem (n - 1, k - 1); Or we put any sticks that is not the tallest (there are n - 1 options), which reduce to subproblem (n - 1, k).

    class Solution {
        private long[][] dp;
        private int mod = (int)1e9 + 7;
        public int rearrangeSticks(int n, int k) {
            dp = new long[n + 1][k + 1];
            for(int i = 0; i <= n; i++) {
                Arrays.fill(dp[i], -1);
            }
            for(int i = 0; i <= k; i++) {
                dp[i][i] = 1;
            }
            for(int i = 1; i <= n; i++) {
                dp[i][0] = 0;
            }
            compute(n, k);
            return (int)(dp[n][k]);
        }
        
        private long compute(int n, int k) {
            if(dp[n][k] >= 0) {
                return dp[n][k];
            }
            dp[n][k] = 0;
            dp[n][k] = (dp[n][k] + compute(n - 1, k - 1)) % mod;
            dp[n][k] = (dp[n][k] + compute(n - 1, k) * (n - 1) % mod) % mod;
            // long p = n - 1;
            // for(int m = n - 2; m >= k - 1; m--) {
            //     dp[n][k] = (dp[n][k] + compute(m, k - 1) * p % mod) % mod;
            //     p = p * m % mod;
            // }
            return dp[n][k];
        }
    }
  • 相关阅读:
    操作正则表达式的公共类
    验证码类
    强制转化常用函数
    实现Base64编码与其它编码转换的类
    关于任务管理器踩过的坑,程序员必看!
    每次找Internet选项感到抓狂?一键打开!
    教你避过安装TensorFlow的两个坑
    HTML中id与name的通俗区别
    VS code代码对齐快捷键
    form和table的区别
  • 原文地址:https://www.cnblogs.com/lz87/p/16015244.html
Copyright © 2020-2023  润新知