⭐️前面的话⭐️
本篇文章介绍【1079. 活字印刷】题解,算法标签:【DFS】, 【哈希表】, 【计数】,展示语言c++/java。
📒博客主页:未见花闻的博客主页
🎉欢迎关注🔎点赞👍收藏⭐️留言📝
📌本文由未见花闻原创,CSDN首发!
📆首发时间:🌴2023年5月19日🌴
✉️坚持和努力一定能换来诗与远方!
💭推荐书籍:📚《算法》,📚《算法导论》
💬参考在线编程网站:🌐牛客网🌐力扣
博主的码云gitee,平常博主写的程序代码都在里面。
博主的github,平常博主写的程序代码都在里面。
🍭作者水平很有限,如果发现错误,一定要及时告知作者哦!感谢感谢!
📌导航小助手📌
⭐️1079. 活字印刷⭐️
🔐题目详情
难度中等
你有一套活字字模 tiles
,其中每个字模上都刻有一个字母 tiles[i]
。返回你可以印出的非空字母序列的数目。
注意: 本题中,每个活字字模只能使用一次。
示例 1:
输入:"AAB"
输出:8
解释:可能的序列为 "A", "B", "AA", "AB", "BA", "AAB", "ABA", "BAA"。
示例 2:
输入:"AAABBC"
输出:188
示例 3:
输入:"V"
输出:1
提示:
1 <= tiles.length <= 7
tiles
由大写英文字母组成
💡解题思路
中国文化博大精深,活字印刷术是我国四大发明之一,是世界印刷史一次伟大的技术革命,非常牛逼…跑偏了。
思路1:枚举全排列+set计数
本题翻译一下,其实就是求所有全排列以及子串全排列得到的不重复字符串的种数,最简单直接的思路就是搜索咯,数据范围只有7
,非常小,可以直接利用DFS枚举所有的全排列,利用set查重,不会超时。
第一步,使用set数据结构对所有枚举的排列情况进行计数,一个布尔数组用来判断对应某字符是否已经使用过,维护一个字符串来保存搜索的序列。
第二步,进行DFS搜索,每进入一个dfs函数栈帧,就添加所有可能能够添加的字母(未使用过的),并标记已使用,每搜索到一个结果,就将结果放入set对象中,直到所有字母都使用过为止,每次递归回来表示包含当前字母的所有结果已经搜索完毕,需要回溯。
第三步,set的结果数就是答案,注意将空集排除。
时间复杂度: O ( n × n ! ) O(n \times n!) O(n×n!)
空间复杂度: O ( n × n ! ) O(n \times n!) O(n×n!)
思路2:哈希表计数+DFS搜索
因为枚举的所有结果数太大了,利用set去重开销非常大,另外一个思路就是先统计每个字母出现的次数,然后利用dfs按照字母表顺序进行搜索,如果搜索的字母够用就进一步进行搜索,并将对应的数目减去1
,表示使用了这个字母,进入下一层搜索,搜索完毕后,该字母没有被选中了,将对应的计数加上1
。
第一步,使用哈希表计数。
第二步,进行dfs搜索,每次选择数量大于0的字母,因为每一层每种字母只会被搜索一次,不会存在重复问题,直接利用一个变量累加计数就行。
第三步,排除空集,返回搜索结果的数目。
时间复杂度: O ( n × n ! ) O(n \times n!) O(n×n!)
空间复杂度: O ( n ) O(n) O(n)
🔑源代码
思路1:枚举全排列+set计数
c++代码:
class Solution {
public:
const static int N = 8;
set<string> set;
string s;
int n;
bool st[N];
void dfs(int u, string path)
{
if (u > n) return;
set.insert(path);
for (int i = 0; i < n; i++)
{
if (st[i]) continue;
st[i] = true;
dfs(u + 1, path + s[i]);
//回溯
st[i] = false;
}
}
int numTilePossibilities(string tiles) {
s = tiles;
n = s.size();
memset(st, 0, sizeof(st));
dfs(0, "");
return set.size() - 1;
}
};
java代码:
class Solution {
Set<String> set = new HashSet<>();
String s;
boolean[] st;
private void dfs(int u, StringBuilder ss) {
if (u > s.length()) return;
set.add(ss.toString());
for (int i = 0; i < s.length(); i++) {
if (st[i]) continue;
st[i] = true;
ss.append(s.charAt(i));
dfs(u + 1, ss);
//回溯
ss.deleteCharAt(ss.length() - 1);
st[i] = false;
}
}
public int numTilePossibilities(String tiles) {
s = tiles;
st = new boolean[s.length()];
dfs(0, new StringBuilder());
return set.size() - 1;
}
}
思路2:哈希表计数+DFS搜索
c++代码:
class Solution {
public:
int cnt[26];
int n;
int ans;
void dfs(int u)
{
if (u == n) return;
for (int i = 0; i < 26; i++)
{
if (cnt[i] > 0)
{
cnt[i]--;
ans++;
dfs(u + 1);
cnt[i]++;
}
}
}
int numTilePossibilities(string tiles) {
n = tiles.size();
memset(cnt, 0, sizeof(cnt));
//哈希计数
for (int i = 0; i < n; i++) cnt[tiles[i] - 'A']++;
dfs(0);
return ans;
}
};
java代码:
class Solution {
int[] cnt = new int[26];
int n;
int ans;
private void dfs(int u) {
if (u == n) return;
for (int i = 0; i < 26; i++) {
if (cnt[i] > 0) {
cnt[i]--;
ans++;
dfs(u + 1);
cnt[i]++;
}
}
}
public int numTilePossibilities(String tiles) {
n = tiles.length();
char[] cs = tiles.toCharArray();
//计数
Arrays.fill(cnt, 0);
for (int i = 0; i < n; i++) cnt[cs[i] - 'A']++;
ans = 0;
dfs(0);
return ans;
}
}
🌱总结
DFS搜索,哈希表计数,StringBuilder类的使用。