小红的二叉树计数
题目描述
小红定义一个二叉树为“好二叉树”,当且仅当该二叉树所有节点的孩子数量为偶数(0
或者 2
)。小红想知道,n
个节点组成的好二叉树,共有多少种不同的形态?答案请对 10^9+7
取模。
数据范围
1 ≤ n ≤ 3000
解题思路
- 所有好二叉树的节点的数量均为奇数;
- 一棵二叉树的形态由其左子树和右子树的形态决定。
代码实现
int cntOfTrees(int n) {
const int N = 3e3 + 5, MOD = 1e9 + 7;
long long dp[N] = {0};
// 节点个数为偶数时无法构成好二叉树
if (!(n & 1)) return 0;
dp[1] = dp[3] = 1;
for (int i = 5; i <= n; i += 2) {
for (int j = 1, k = i - 1; j < k; j += 2) {
dp[i] += (dp[j] * dp[k - j]) % MOD;
dp[i] %= MOD;
}
}
return (int) dp[n];
}
时间复杂度:O(n^2)
空间复杂度:O(n^2)
小红的可爱串
题目描述
小红定义一个字符串是可爱串,当且仅当该字符串包含子序列 red
,且不包含子串 red
。
我们定义子序列为字符串中可以不连续的一段,而子串则必须连续。例如 rderd
包含子序列 red
,且不包含子串 red
,因此该字符串为可爱串。
小红想知道,长度为 n
的、仅由 r
、e
、d
三种字母组成的字符串中,有多少是可爱串?答案请对 10^9+7
取模。
数据范围
1 ≤ n ≤ 10^5
解题思路
- 包含子串
red
的字符串的集合 ∈ 包含子序列red
的字符串集合。 - 可爱串的数量 = 包含子序列
red
的字符串的数量 - 包含子串red
的字符串的数量 。 如何构造包含子串
red
的字符串(记字符串为s
) ?- 令
f[i]
= 长度为i
的字符串中包含子串red
的字符串的数量。 分为两种情况
- 若
s[i]
为r
或e
,则s[i]
必定不影响f[i]
,f[i] = f[i-1] + f[i-1]
。 若
s[i]
为d
- 若
s[i]
不影响f[i]
,即s[1..i-1]
已包含子串red
,则f[i] = f[i-1]
。 - 若
s[i]
影响f[i]
,即s[1..i-3]
不含子串red
,但s[i-2..i-1]= re
,加上s[i]
即可构成子串red
,则f[i] = 3^{(i-3)}-f[i-3]
。
- 若
- 若
- 综上,
f[i] = 3 × f[i-1] + 3^{(i-3)}-f[i-3]
。
- 令
如何构造包含子序列
red
的字符串(记字符串为 s)?- 令
g[i]
= 长度为i
的字符串中包含子序列red
的字符串的数量。 分为两种情况
- 若
s[i]
为r
或e
,则s[i]
必定不影响g[i]
,g[i] = g[i-1] + g[i-1]
。 若
s[i]
为d
- 若
s[i]
不影响g[i]
,即s[1..i-1]
已包含子序列red
,则g[i] = g[i-1]
。 - 若
s[i]
影响g[i]
,即s[1..i-i]
不含子序列red
,但含子序列re
,加上s[i]
即可构成子序列red
,令h[i]
= 长度为i
的字符串中不含子序列red
但含子序列re
的字符串的数量,则g[i] = h[i-1]
。
- 若
- 综上所述,
g[i] = 3 × g[i-1] + h[i-1]
。
- 若
- 令
如何构造不含子序列
red
且含子序列re
的字符串,即如何计算f[i]
(记字符串为 s)?- 令
h[i]
= 长度为i
的字符串中不含子序列red
但含子序列re
的字符串的数量(第4点中已进行如此假设)。 s[i]
是否能为d
?包含子序列re
、不包含子序列red
、s[i] = d
,满足这三个条件的字符串不存在,故不考虑s[i] = d
的情况。分为两种情况
- 若
s[i]
为r
,则s[i]
必定不影响h[i]
,h[i] = h[i-1]
。 若
s[i]
为e
- 若
s[i]
不影响h[i]
,即s[1..i-1]
已包含子序列re
且不含子序列red
,则h[i] = h[i-1]
。 若
s[i]
影响h[i]
,即s[1..i-1]
不满足(已包含子序列re
且不含子序列red
),但含有子序列r
,加上s[i]
即可构成子序列re
。令条件
A
= 不满足(已包含子序列re
且不含子序列red
)但含有子序列r
,设满足条件A
的字符串为t
,下面考虑如何构造t
。t
的长度为i-1
,t
至少包含一个子序列r
,手动将一个子序列r
填入t
,记作R
,并规定手动填入的R
的左边空位不能填入r
,R
有i-1
个位置可以选择,以R
为界R
左边的空位只可填入e
或d
,这是因为,为了防止重复计算,人为规定R
的左边空位不能填r
。R
右边的空位只可填入r
或d
,这是因为,R
右边空位若填入e
,则s[1..i-1]
则含有子序列re
,s[i]
对h[i]
无影响,这与前置条件相矛盾,故R
右边空位不可以填入e
。
经过分析,
R
左边和右边空位均只可以填入两种字符,共有i-2
个空位,共有2^{(i-2)}
种填充方式,又因为R
有i-1
中填充方式,故t
的数量有(i-1) × 2^{(i-2)}
,也即h[i] = (i-1) × 2^{(i-2)}
。
- 若
- 综上所述,
h[i] = 2 × h[i-1] + (i-1) × 2^{(i-2)}
。
- 若
- 令
- 综上所述,长度为
n
的可爱串的数量为g[n]-f[n]
。
代码实现
typedef long long ll;
const int N = 1e5 + 5, MOD = 1e9 + 7;
ll f[N], g[N], h[N];
// 快速幂
ll ksm(ll x, ll n) {
ll res = 1 % MOD;
while (n) {
if (n & 1)res = res * x % MOD;
x = x * x % MOD;
n >>= 1;
}
return res;
}
int kawaiiStrings(int n) {
// f[i] = 长度为 i 的字符串中包含子串 red 的字符串的数量
for (int i = 3; i <= n; i++)
f[i] = (f[i - 1] * 3 + ksm(3, i - 3) - f[i - 3]) % MOD;
// h[i] = 长度为 i 的字符串中不含子序列 red 但含子序列 re 的字符串的数量
for (int i = 2; i <= n; i++)
h[i] = (h[i - 1] * 2 + (i - 1) * ksm(2, i - 2)) % MOD;
// g[i] = 长度为 i 的字符串中包含子序列 red 的字符串
for (int i = 3; i <= n; i++)
g[i] = (g[i - 1] * 3 + h[i - 1]) % MOD;
return int((g[n] - f[n] + MOD) % MOD);
}
时间复杂度:O(n)
空间复杂度:O(n)
小红的元素乘积
题目描述
小红定义一个数为“完美数”,当且仅当该数仅有一个非零数字。例如 5000,4,1,10,200
都是完美数。小红拿到了一个大小为 n
的数组,她希望选择两个元素,满足它们的乘积为完美数。小红想知道,共有多少种不同的取法?
数据范围
1 ≤ n ≤ 2000
1 ≤ a_i ≤ 10^9
解题思路
枚举判断即可。
代码实现
typedef long long ll;
bool check(ll x) {
if (x < 10)return true;
string s = to_string(x);
for (int i = 1; i < s.size(); i++)
if (s[i] != '0')return false;
return true;
}
int perfectPair(vector<int> &arr) {
int n = arr.size(), res = 0;
if (n < 2)return 0;
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
if (check((ll) arr[i] * arr[j]))res++;
}
}
return res;
}
时间复杂度:O(n^2)
空间复杂度:O(1)
END
温馨提示:由于本平台不能完全支持 Markdown
语法,更好的 Markdown
阅读体验请移步至 A 或 B 或 C / 可点击阅读原文。
题目来源:腾讯音乐娱乐集团2024校园招聘-前端开发笔试(II)
文章声明:题目来源 牛客 平台,如有侵权,请联系删除!
文章文档:公众号 字节幺零二四
回复关键字可获取本文文档。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。