面试经典回溯题

Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情

面试题 括号(一)

问题描述

  • 括号。设计一种算法,打印n对括号的所有合法的(例如,开闭一一对应)组合。

  • 说明:解集不能包含重复的子集。

  • 例如,给出 n = 3,生成结果为:

["((()))", "(()())", "(())()", "()(())", "()()()"]
复制代码
  • n = 4,生成结果为:
["(((())))","((()()))","((())())","((()))()","(()(()))","(()()())","(()())()","(())(())","(())()()","()((()))","()(()())","()(())()","()()(())","()()()()"]
复制代码

思路分析

  • 暴力方法:枚举出所有组合,然后对每一个组合进行判断。对于输入为 n n ,一共有 2 n 2 ^ n 种组合情况,并且对每一个进行判断。所以总的时间复杂度为 O ( n 2 n ) O(n*2 ^ n) ,也就是说在提交的时候可能会超时。
  • 递归回溯 + 剪枝:通过往有效的字符串组合不断添加 '(' 或 ')' ,如果所组合的字符串已经无效(例如右括号数量已经多于左括号数量了)。就可以停止当前递归,就是所谓的剪枝。直到有效括号数等于 n n 加入返回集合,并进行剪枝。

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"]
复制代码

思路分析

  • 在字符串中会有一个或者多个一样的字符,如果直接递归回溯就会出现多个一样的字符串。
  • 为了保证方便对字符进行分析,先对字符按照 a s c l l ascll 码 进行排序。
  • 我们需要对已经访问过的下标进行标记,并在每一轮递归时进行剔除是否出现重复的字符。当完整遍历字符串集合时,就加入返回集合。

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;
        }
    }
}
复制代码

总结

  • 回溯题型在面试中也是比较常见的题型,我们可以通过多练习该题型题目就可以掌握比较常见的题目了。

Supongo que te gusta

Origin juejin.im/post/7074159552375029767
Recomendado
Clasificación