【1641. 统计字典序元音字符串的数目】

来源:力扣(LeetCode)

描述:

给你一个整数 n,请返回长度为 n 、仅由元音 (a, e, i, o, u) 组成且按 字典序排列 的字符串数量。

字符串 s字典序排列 需要满足:对于所有有效的 is[i] 在字母表中的位置总是与 s[i+1] 相同或在 s[i+1] 之前。

示例 1:

输入:n = 1
输出:5
解释:仅由元音组成的 5 个字典序字符串为 ["a","e","i","o","u"]

示例 2:

输入:n = 2
输出:15
解释:仅由元音组成的 15 个字典序字符串为
["aa","ae","ai","ao","au","ee","ei","eo","eu","ii","io","iu","oo","ou","uu"]
注意,"ea" 不是符合题意的字符串,因为 'e' 在字母表中的位置比 'a' 靠后

示例 3:

输入:n = 33
输出:66045

提示:

  • 1 <= n <= 50

方法一:动态规划

分别使用数字 0,1,2,3,4 代表元音字符 ‘a’,‘e’,‘i’,‘o’,‘u’。记 dp[i][j] 表示长度为 i + 1,以 j 结尾的按字典序排列的字符串数量,那么状态转移方程如下:

1
因此长度为 n 的按字典序排列的字符串数量为 ∑ k = 0 4 \sum_{k=0}^4 k=04dp[n−1][j]。因为 dp[i] 的计算只涉及 dp[i−1] 部分的数据,同时 dp[i] 等价于 dp[i−1] 的前缀和,我们可以只使用一维数组进行存储,同时在一维数组进行原地修改。

代码:

class Solution {
public:
    int countVowelStrings(int n) {
        vector<int> dp(5, 1);
        for (int i = 1; i < n; i++) {
            for (int j = 1; j < 5; j++) {
                dp[j] += dp[j - 1];
            }
        }
        return accumulate(dp.begin(), dp.end(), 0);
    }
};

执行用时:0 ms, 在所有 C++ 提交中击败了100.00%的用户
内存消耗:5.8 MB, 在所有 C++ 提交中击败了72.77%的用户
复杂度分析
时间复杂度:O(n×Σ),其中 n 是字符串的长度,Σ=5 表示元音字符集大小。
空间复杂度:O(Σ)。

方法二:组合数学

对于一个按字典序排列的元音字符串,假设 ‘a’,‘e’,‘i’,‘o’,‘u’ 的起始下标分别为 ia,ie,ii,io,iu,显然 ia = 0 且 0 ≤ ie ≤ ii ≤ io ≤ iu ≤ n。因此字典序元音字符串的数目等于满足 0 ≤ ie ≤ ii ≤ io ≤ iu ≤ n 的 (ie,ii,io,iu) 的取值数目。想要直接求得 (ie,ii,io,iu) 的取值数目是十分困难的,我们可以作以下转换:

  • ie = i′e
  • i′i = ii+1
  • i′o = io+2
  • i′u = iu+3

由 0 ≤ ie ≤ ii ≤ io ≤ iu ≤ n 可知 0 ≤ i′e ≤ i′i ≤ i′o ≤ i′u ≤ n + 3。每一个 (ie,ii,io,iu) 都唯一地对应一个 (i′e,i′i,i′o,i′u),因此 (ie,ii,io,iu) 的取值数目等于 (i′e,i′i,i′o,i′u) 的取值数目。(i′e,i′i,i′o,i′u) 等价于从 n + 4 个数中选取互不相等的 4 个数,因此 (i′e,i′i,i′o,i′u) 的取值数目等于组合数 C n + 4 4 C_{n+4}^4 Cn+44

代码:

class Solution {
public:
    int countVowelStrings(int n) {
        return (n + 1) * (n + 2) * (n + 3) * (n + 4) / 24;
    }
};

执行用时:0 ms, 在所有 C++ 提交中击败了100.00%的用户
内存消耗:5.8 MB, 在所有 C++ 提交中击败了75.32%的用户
复杂度分析
时间复杂度:O(Σ),其中 Σ=5 表示元音字符集大小。
空间复杂度:O(1)。
author:LeetCode-Solution

你可能感兴趣的:(LeetCode,算法,leetcode,数据结构,C++)