1 题目
你有一套活字字模 tiles,其中每个字模上都刻有一个字母 tiles[i]。返回你可以印出的非空字母序列的数目。
注意:本题中,每个活字字模只能使用一次。
示例 1:
输入:“AAB”
输出:8
解释:可能的序列为 “A”, “B”, “AA”, “AB”, “BA”, “AAB”, “ABA”, “BAA”。
示例 2:
输入:“AAABBC”
输出:188
提示:
1 <= tiles.length <= 7
tiles 由大写英文字母组成
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/letter-tile-possibilities
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
2 Java
2.1 方法一(回溯,以26个字母为分支)
先统计有几个A、几个B……几个Z可选
再以26个字母为分支
这种回溯不存在重复的情况
class Solution {
public int numTilePossibilities(String tiles) {
// 先统计每个字母的出现次数
int[] counter = new int[26];
for (int i = 0; i < tiles.length(); i++) {
counter[tiles.charAt(i) - 'A']++;
}
numTilePossibilitiesHelper(counter);
return res;
}
int res = 0;
public int numTilePossibilitiesHelper(int[] counter){
// 无 if 判断是否记录路径;因为本题无需递归到底(叶节点)
// for 循环 多路选择
for (int i = 0; i < counter.length; i++) {
// 做选择
if(counter[i] == 0){
continue;
}
counter[i]--;
res++; // 无需递归到底,每添加一个字符就算一个新字符
numTilePossibilitiesHelper(counter); // 只需要求数量,不记录结果,所以参数不含路径
// 撤销选择
counter[i]++;
}
}
}
2.2 方法二(回溯,以字符串剩余字符为分支)
即AABBB第一次选择就有5条分支,第二次选择就有4条分支
所以这种回溯方式,会存在重复的情况,需要用set去重
class Solution {
public int numTilePossibilities(String tiles) {
Set<String> set = new HashSet<>();
numTilePossibilitiesHelper(tiles, "", set);
return set.size();
}
// tiles是待选择字符串,subS是已从tiles抽离出来的字符按序构成的字符串,等待加入set中
// set记录所有利用tiles中字符排列组合后 可构成的字符串
public void numTilePossibilitiesHelper(String tiles, String subS, Set<String> set) {
// if 判断 是否记录结果
if(subS.length() != 0){
set.add(subS);
}
// for 循环 多路选择
for (int i = 0; i < tiles.length(); i++) {
// 做选择;撤销选择
// 每次选择一个字符,从字符串中删除该字符,进入下一层循环
numTilePossibilitiesHelper(tiles.substring(0, i) + tiles.substring(i + 1, tiles.length()), subS + tiles.charAt(i), set);
}
}
}