构成指定长度字符串的个数
原文链接
原文来自牛客网:华为OD机试统一考试D卷C卷 - 构成指定长度字符串的个数
题目描述:构成指定长度字符串的个数
给定 M(0 < M ≤ 30)个字符(a-z),从中取出任意字符(每个字符只能用一次)拼接成长度为 N(0 < N ≤ 5)的字符串,
要求相同的字符不能相邻,计算出给定的字符列表能拼接出多少种满足条件的字符串,
输入非法或者无法拼接出满足条件的字符串则返回0。
输入描述
给定的字符列表和结果字符串长度,中间使用空格(" ")拼接
输出描述
满足条件的字符串个数
用例1
输入
aab 2
输出
2
输入
abc 2
输出
6
用例2
输入
abc 2
解题思路
使用递归和回溯的思想来生成不同的字符串。具体的逻辑如下:
首先,我们定义一个函数generateDistinctStrings,这个函数接收以下参数:可用字符集s,目标字符串长度length,当前已生成的字符串current,已生成的结果集result,以及一个标记数组used,用来记录每个字符是否已被使用。
在generateDistinctStrings函数中,首先检查当前已生成的字符串current的长度是否等于目标长度length。如果等于,说明我们已经生成了一个满足长度要求的字符串,将其添加到结果集result中,然后返回。
如果当前字符串current的长度还未达到目标长度length,我们就需要继续添加字符。此时,我们遍历可用字符集s中的每一个字符。对于每一个字符,我们首先检查它是否已经被使用(通过查看used数组),以及它是否与current的最后一个字符相同。如果字符已经被使用,或者与current的最后一个字符相同,我们就跳过这个字符,继续检查下一个字符。
如果一个字符未被使用,且与current的最后一个字符不同,我们就将它添加到current的末尾,然后标记这个字符为已使用,接着递归调用generateDistinctStrings函数,以生成下一个字符。
在递归调用返回后,我们需要取消对当前字符的使用标记,以便在后续的遍历中可以再次使用这个字符。这就是回溯的思想,即撤销之前的选择,尝试其他的选择。
伪代码:
函数 generateDistinctStrings(s, length, current, result, used)
如果 current的长度 等于 length
将 current 添加到 result
返回
对于 s中的每一个字符 c
如果 c已被使用 或者 c与current的最后一个字符相同
继续下一次循环
标记 c为已使用
generateDistinctStrings(s, length, current + c, result, used)
取消标记 c的使用状态
C++
#include <iostream>
#include <unordered_set>
#include <vector>
#include <sstream>
using namespace std;
// 递归生成满足条件的不同字符串
void generateDistinctStrings(string s, int length, string current, unordered_set<string>& result, vector<bool>& used) {
// 当生成的字符串长度等于指定长度时,将其加入到结果集中
if (current.length() == length) {
result.insert(current);
return;
}
// 遍历字符串中的字符
for (int i = 0; i < s.length(); i++) {
// 判断字符是否已经被使用,或者当前字符与前一个字符相同
if (used[i] || (current.length() > 0 && current.back() == s[i])) {
continue; // 如果字符已被使用或与前一个字符相同,则跳过当前字符
}
used[i] = true; // 标记当前字符为已使用
// 递归调用生成下一个字符
generateDistinctStrings(s, length, current + s[i], result, used);
used[i] = false; // 取消标记当前字符的使用状态,以便下一次遍历
}
}
// 计算满足条件的不同字符串的数量
int countDistinctStrings(string s, int length) {
// 创建一个集合来存储不同的字符串
unordered_set<string> distinctStrings;
// 创建一个列表来标记字符串中的字符是否已经被使用
vector<bool> used(s.length(), false);
// 调用generateDistinctStrings方法生成满足条件的不同字符串
generateDistinctStrings(s, length, "", distinctStrings, used);
// 打印生成的所有不同的字符串
// for (auto& str : distinctStrings) {
// cout << str << endl;
// }
// 返回不同字符串的数量
return distinctStrings.size();
}
int main() {
string input;
getline(cin, input);
// 将输入的字符串按空格分割为两部分,分别为字符串和长度
string str;
int length;
istringstream iss(input);
iss >> str >> length;
// 调用countDistinctStrings方法计算满足条件的不同字符串的数量
int count = countDistinctStrings(str, length);
// 输出计算结果
cout << count << endl;
return 0;
}