🍭 大家好这里是清隆学长 ,一枚热爱算法的程序员
✨ 本系列打算持续跟新华为OD-C/D卷的三语言AC题解
💻 ACM银牌🥈| 多次AK大厂笔试 | 编程一对一辅导
👏 感谢大家的订阅➕ 和 喜欢💗
📎在线评测链接
https://app5938.acapp.acwing.com.cn/contest/2/problem/OD1088
🌍 评测功能需要 ⇒ 订阅专栏 ⇐ 后私信联系清隆解锁~
🍓OJ题目截图
文章目录
- 📎在线评测链接
- 🍓OJ题目截图
- 🌲 LYA的字符串拼接游戏
- 问题描述
- 输入格式
- 输出格式
- 样例输入
- 样例输出
- 样例解释
- 样例输入
- 样例输出
- 样例解释
- 数据范围
- 题解
- 参考代码
🌲 LYA的字符串拼接游戏
问题描述
LYA最近迷上了一款字符串拼接游戏。游戏规则如下:
给定一个由小写字母组成的字符集合,以及一个正整数 N N N。从字符集合中任意取出字符(每个字符只能用一次),拼接成一个长度为 N N N 的字符串,要求相邻的字符不能相同。
请帮助LYA计算出,给定的字符集合能拼接出多少种满足条件的字符串。如果输入非法或无法拼接出满足条件的字符串,则输出 0 0 0。
输入格式
输入为一行,包含一个由小写字母组成的字符串和一个正整数 N N N,两者之间用一个空格分隔。
- $1 \le $ 字符串长度 ≤ 29 \le 29 ≤29
- 1 ≤ N ≤ 5 1 \le N \le 5 1≤N≤5
输出格式
输出一个整数,表示能拼接出的满足条件的字符串个数。
样例输入
abc 1
样例输出
3
样例解释
给定的字符集合为 abc
,结果字符串长度为
1
1
1,可以拼接出 a
、b
、c
三种字符串,因此输出
3
3
3。
样例输入
dde 2
样例输出
2
样例解释
给定的字符集合为 dde
,结果字符串长度为
2
2
2,可以拼接出 de
、ed
两种字符串,因此输出
2
2
2。
数据范围
- $1 \le $ 字符串长度 ≤ 29 \le 29 ≤29
- 1 ≤ N ≤ 5 1 \le N \le 5 1≤N≤5
题解
本题可以用回溯法(DFS)来解决。
我们定义一个布尔数组 vis
来记录每个字符是否被使用过。然后从字符集合的第一个字符开始,尝试将它加入结果字符串。如果当前字符没有被使用过,且与结果字符串的最后一个字符不同,就将它加入结果字符串,并标记为已使用。
接下来,我们继续尝试从剩余的未使用字符中选择下一个字符,直到结果字符串的长度达到 N N N。如果能够成功构造出一个满足条件的字符串,就将答案加一。
在尝试每一步时,我们都需要跳过重复的字符,以避免重复计算。这可以通过对字符集合进行排序,然后在遍历时跳过连续相同的字符来实现。
时间复杂度为 O ( N ! × M ) O(N! \times M) O(N!×M),其中 N N N 为结果字符串的长度, M M M 为字符集合的长度。空间复杂度为 O ( M ) O(M) O(M),用于存储字符集合和访问数组。
参考代码
- Python
from itertools import permutations
def count_strings(chars, n):
res = 0
for perm in permutations(chars, n):
if all(perm[i] != perm[i+1] for i in range(n-1)):
res += 1
return res
chars, n = input().split()
n = int(n)
print(count_strings(chars, n))
- Java
import java.util.*;
public class Main {
static int k;
static char[] cs;
static int res;
static boolean[] vis;
static StringBuilder sb = new StringBuilder();
static int n;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String s = sc.next();
n = s.length();
k = sc.nextInt();
cs = s.toCharArray();
vis = new boolean[n];
Arrays.sort(cs);
dfs(0);
System.out.println(res);
}
static void dfs(int u) {
if (u == k) {
res++;
return;
}
for (int i = 0; i < n; i++) {
if (vis[i]) {
continue;
}
if (i > 0 && cs[i] == cs[i - 1] && !vis[i - 1]) {
continue;
}
if (sb.length() > 0 && sb.charAt(sb.length() - 1) == cs[i]) {
continue;
}
vis[i] = true;
sb.append(cs[i]);
dfs(u + 1);
sb.deleteCharAt(sb.length() - 1);
vis[i] = false;
}
}
}
- Cpp
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int n, k;
string cs;
int res = 0;
vector<bool> vis;
string sb;
void dfs(int u) {
if (u == k) {
res++;
return;
}
for (int i = 0; i < n; i++) {
if (vis[i]) {
continue;
}
if (i > 0 && cs[i] == cs[i - 1] && !vis[i - 1]) {
continue;
}
if (!sb.empty() && sb.back() == cs[i]) {
continue;
}
vis[i] = true;
sb.push_back(cs[i]);
dfs(u + 1);
sb.pop_back();
vis[i] = false;
}
}
int main() {
cin >> cs >> k;
n = cs.length();
vis.resize(n, false);
sort(cs.begin(), cs.end());
dfs(0);
cout << res << endl;
return 0;
}