Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情。
面试题 括号(一)
问题描述
-
括号。设计一种算法,打印n对括号的所有合法的(例如,开闭一一对应)组合。
-
说明:解集不能包含重复的子集。
-
例如,给出 n = 3,生成结果为:
["((()))", "(()())", "(())()", "()(())", "()()()"]
复制代码
- n = 4,生成结果为:
["(((())))","((()()))","((())())","((()))()","(()(()))","(()()())","(()())()","(())(())","(())()()","()((()))","()(()())","()(())()","()()(())","()()()()"]
复制代码
思路分析
- 暴力方法:枚举出所有组合,然后对每一个组合进行判断。对于输入为 ,一共有 种组合情况,并且对每一个进行判断。所以总的时间复杂度为 ,也就是说在提交的时候可能会超时。
- 递归回溯 + 剪枝:通过往有效的字符串组合不断添加 '(' 或 ')' ,如果所组合的字符串已经无效(例如右括号数量已经多于左括号数量了)。就可以停止当前递归,就是所谓的剪枝。直到有效括号数等于 加入返回集合,并进行剪枝。
AC 代码
class Solution {
private List<String> data = new ArrayList<>();
private StringBuilder sb = new StringBuilder();
public List<String> generateParenthesis(int n) {
backtrack(0,0,n);
return data;
}
private void backtrack(int left, int right, int n) {
// 字符无效,进行剪枝.
if (left < right || left > n || right > n) return;
// 括号对数等于 n ,停止当前递归,加入返回集合.
if (left == n && right == n) {
data.add(sb.toString());
return;
}
sb.append('(');
backtrack(left + 1, right,n);
sb.deleteCharAt(left + right);
sb.append(')');
backtrack(left, right + 1,n);
sb.deleteCharAt(left + right);
}
}
复制代码
面试题 有重复字符串的排列组合(二)
题目描述
- 有重复字符串的排列组合。编写一种方法,计算某字符串的所有排列组合。
- 示例 1
输入:S = "qqe"
输出:["eqq","qeq","qqe"]
复制代码
- 示例 2
输入:S = "ab"
输出:["ab", "ba"]
复制代码
思路分析
- 在字符串中会有一个或者多个一样的字符,如果直接递归回溯就会出现多个一样的字符串。
- 为了保证方便对字符进行分析,先对字符按照 码 进行排序。
- 我们需要对已经访问过的下标进行标记,并在每一轮递归时进行剔除是否出现重复的字符。当完整遍历字符串集合时,就加入返回集合。
AC 代码
class Solution {
private char[] cs;
private int n;
private boolean[] visited;
private List<String> data = new ArrayList<>();
private StringBuilder sb = new StringBuilder();
public String[] permutation(String s) {
cs = s.toCharArray();
n = cs.length;
// 字符下标访问标记
visited = new boolean[n];
// 对字符集合进行排序
Arrays.sort(cs);
backtrack();
return data.toArray(new String[0]);
}
private void backtrack() {
if (sb.length() == n) {
data.add(sb.toString());
return;
}
for (int i = 0; i < n; i++) {
if (visited[i]) continue;
// 去除重复字符组合
if (i != 0 && cs[i - 1] == cs[i] && !visited[i - 1]) continue;
sb.append(cs[i]);
visited[i] = true;
backtrack();
sb.deleteCharAt(sb.length() - 1);
visited[i] = false;
}
}
}
复制代码
总结
- 回溯题型在面试中也是比较常见的题型,我们可以通过多练习该题型题目就可以掌握比较常见的题目了。