1 条题解
-
0
📝 题目大意
给定 个字符串,要求找出一个最长的字符串,使得该字符串能通过重新排列任意一个 中的字符得到。若有多个最长字符串,输出字典序最小的。如果只有空串满足条件,输出空行。
💡 解题思路
-
题目分析:题目本质上是在求所有 个字符串的公共字符多重集的最大可能字符串。由于可以任意重排,字符顺序不重要,只关心每个字符的可用数量。将问题转化为:对于每个小写字母 ,它在答案中最多能出现多少次?显然,答案中 的出现次数不能超过任意一个 中 的出现次数,即 的可用次数等于所有串中 出现次数的最小值。
-
算法推导:
- 朴素想法:枚举所有可能的子串/子序列?不可行, 但组合数太多。
- 关键洞察:字符之间独立——字母
a能放多少个和字母b能放多少个互不影响。因此可以按字符独立统计。 - 具体做法:用一个二维数组
a[i][c]记录第 个字符串中字符 (,对应a~z)的出现次数。然后对每个字符 ,取所有 个串中该字符出现次数的最小值,记作b[c]。答案就是把字符 重复b[0]次、字符 重复b[1]次……字符 重复b[25]次,依次拼接。 - 为什么字典序最小?因为我们按
a到z的顺序输出,所有a放在最前面,自然保证了字典序最小(任何其他排列都会在某个位置出现更大的字符)。
-
边界与细节:
b[i]初始化为一个充分大的数(代码中为325125),确保min运算正确。注意 ,,所以每个字符最多出现 50 次,325125足够了。- 若所有字符的
b[i]均为 0,则不会输出任何字符,即输出空行,符合题意。 - 字符转数字索引:
s[i][j] - 'a',输出时反向转换:(char)('a' + i)。 - 数据范围 ,,所以 非常轻松。
⏱️ 复杂度分析
- 时间复杂度:统计每个字符串的字符频率需要 ,最坏 次操作。求每个字符的最小值需要 ,输出需要 。总复杂度 ,即 。
- 空间复杂度:
a[59][59]和b[59]均为常数大小, 额外空间(不计输入字符串存储)。
💻 标准代码 (C++)
#include<bits/stdc++.h> using namespace std; long long n, a[59][59], b[59]; // a[i][c]: 第i个字符串中字符c的出现次数; b[c]: 字符c在所有串中的最小出现次数 string s[59]; int main() { cin >> n; // 将每个字符的最小值初始化为一个足够大的数 for (int i = 0; i <= 25; ++i) { b[i] = 325125; } // 读入每个字符串并统计字符频率 for (int i = 1; i <= n; ++i) { cin >> s[i]; for (int j = 0; j < s[i].size(); ++j) { ++a[i][s[i][j] - 'a']; // 将字符映射到 0~25 } } // 对每个字符,取所有字符串中出现次数的最小值 for (int i = 0; i <= 25; ++i) { for (int j = 1; j <= n; ++j) { if (a[j][i] < b[i]) { b[i] = a[j][i]; } } // 按 a~z 的顺序输出 b[i] 个该字符,保证字典序最小 for (int j = 1; j <= b[i]; ++j) { cout << (char)('a' + i); } } return 0; } -
- 1
信息
- ID
- 841
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- (无)
- 递交数
- 1
- 已通过
- 1
- 上传者