给定一个表示单词列表的字符串 s
。单词中的每个字母都有一个或多个选项。
- 如果有一个选项,则字母按原样表示。
- 如果有多个选项,则用大括号分隔选项。例如,
"{a,b,c}"
表示选项["a", "b", "c"]
。
例如,如果 s = "a{b,c}"
,第一个字符总是 'a'
,但第二个字符可以是 'b'
或 'c'
。原来的列表是 ["ab", "ac"]
。
请你 按字典顺序 ,返回所有以这种方式形成的单词。
示例 1:
输入:s = "{a,b}c{d,e}f" 输出:["acdf","acef","bcdf","bcef"]
示例 2:
输入:s = "abcd" 输出:["abcd"]
提示:
1 <= S.length <= 50
s
由括号'{}'
,','
和小写英文字母组成。s
保证是一个有效的输入。- 没有嵌套的大括号。
- 在一对连续的左括号和右括号内的所有字符都是不同的。
提示 1
All generated strings are of the same size. How can we generate all of these strings?
提示 2
Do a backtracking on which each level of it has to choose one single (e.g. 'a') character or any character of the given parenthesized group (e.g. "{a,b,c}")
解法1:回溯法
算法逻辑
- 初始化一个结果列表
result
来存储所有可能的单词组合。 - 使用一个辅助函数
backtrack
来实现回溯逻辑。这个函数接收当前索引index
,当前构建的单词current
,以及结果列表result
。 - 如果当前索引等于字符串长度,说明已经处理完所有字符,将当前构建的单词添加到结果列表中,并返回。
- 如果当前字符是
{
,说明遇到了一个字符组。找到对应的}
,并获取这个字符组内的所有选项。 - 对于每个选项,将其添加到当前构建的单词中,然后递归调用
backtrack
函数,继续处理下一个字符。 - 如果当前字符不是
{
,直接将其添加到当前构建的单词中,然后递归调用backtrack
函数,继续处理下一个字符。 - 在递归调用结束后,需要将当前字符从构建的单词中移除,以便回退到上一步,尝试其他选项。
Java版:
class Solution {
public String[] expand(String s) {
List<String> result = new ArrayList<>();
backtrack(s, 0, new StringBuffer(), result);
Collections.sort(result);
return result.toArray(new String[0]);
}
private void backtrack(String s, int index, StringBuffer current, List<String> result) {
if (index == s.length()) {
result.add(current.toString());
return;
}
char ch = s.charAt(index);
if (ch == '{') {
int end = s.indexOf("}", index);
String[] choices = s.substring(index + 1, end).split(",");
for (String choice : choices) {
current.append(choice);
backtrack(s, end + 1, current, result);
current.deleteCharAt(current.length() - 1);
}
} else {
current.append(ch);
backtrack(s, index + 1, current, result);
current.deleteCharAt(current.length() - 1);
}
}
}
Python3版:
class Solution:
def expand(self, s: str) -> List[str]:
def backtrack(index, current, result):
if index == len(s):
result.append(current)
return
if s[index] == '{':
end = s.find("}", index)
choices = s[index + 1 : end].split(",")
for choice in choices:
current += choice
backtrack(end + 1, current, result)
current = current[:-1]
else:
current += s[index]
backtrack(index + 1, current, result)
current = current[:-1]
result = []
backtrack(0, '', result)
result.sort()
return result
解法2: 栈扩展法
这种解法使用栈来存储当前的构建状态,并在遇到字符组时扩展栈中的元素,这种方法在处理过程中对字符组进行展开,类似于树的遍历。
class Solution:
def expand(self, s: str) -> List[str]:
stack = []
i = 0
while i < len(s):
if s[i] == '{':
j = s.find('}', i)
choices = s[i + 1 : j].split(',')
if stack:
temp = []
for c in choices:
temp.extend([item + c for item in stack])
stack = temp
else:
stack = [c for c in choices]
i = j
else:
if stack:
stack = [item + s[i] for item in stack]
else:
stack.append(s[i])
i += 1
stack.sort()
return stack
复杂度分析
- 时间复杂度:O(n ^ 2)。由于我们需要生成所有可能的组合,最坏情况下,每个字符都可能是一个字符组,包含
n
个选项,因此时间复杂度为O(n ^ 2),其中n
是字符串s
的长度。 - 空间复杂度:O(n)。