回溯算法 - 二叉树中和为某一值的路径 && 字符串的排列

目录

1.二叉树中和为某一值的路径

1.1 题目描述

1.2 回溯算法的一般步骤

1.3 解题思路

1.4 代码实现

2. 字符串的排列

2.1 题目描述

2.2 解题思路

2.3 代码实现


1.二叉树中和为某一值的路径

1.1 题目描述

输入一颗二叉树的根节点root和一个整数expectNumber,找出二叉树中结点值的和为
expectNumber的所有路径。
1.该题路径定义为从树的根结点开始往下一直到叶子结点所经过的结点
2.叶子节点是指没有子节点的节点
3.路径只能从父节点到子节点,不能从子节点到父节点
4.总节点数目为n

 

1.2 回溯算法的一般步骤

1. 先添加值 (待选结果)

2. 再判定现有结果是否满足条件 (基于二叉树, 多叉树的穷举的过程, 在穷举的过程中, 要进行剪枝)

3. DFS (深度优先)

4. 回溯 (检测下一个)

1.3 解题思路

1.我们要明确从哪个节点开始.

2.深度优先遍历二叉树.

  • 遍历的过程中我们需要一个一维数组 (ArrayList<Integer>)来添加某条路径上的所有结点的值 (待选结果), 每添加一个值, 我们对应的 expectNumber 就对应减去该结点的值
  • 当该结点的左右子树都为空, 并且 expectNumber == 0 的时候, 此时我们需要一个二维数组 (ArrayList<ArrayList<Integer>>) 将其添加进去

1.4 代码实现

    public void FindPathDFS(TreeNode root, int expectNumber, ArrayList<ArrayList<Integer>> result, ArrayList<Integer> list) {
        if(root == null) {
            return;
        }
        // 添加结果到待选结果中
        list.add(root.val);
        expectNumber -= root.val;
        // 条件判断, 剪枝 (合法判定)
        if(root.left == null && root.right == null && expectNumber == 0) {
            result.add(new ArrayList<Integer>(list));
        }

        // DFS
        FindPathDFS(root.left, expectNumber, result, list);
        FindPathDFS(root.right, expectNumber, result, list);

        // 回溯
        list.remove(list.size() - 1);
    }
    public ArrayList<ArrayList<Integer>> FindPath(TreeNode root,int expectNumber) {
        ArrayList<ArrayList<Integer>> result = new ArrayList<>();
        if(root == null) {
            return result;
        }
        ArrayList<Integer> list = new ArrayList<>();
        FindPathDFS(root, expectNumber, result, list);
        return result;
    }

2. 字符串的排列

2.1 题目描述

输入一个长度为 n 字符串,打印出该字符串中字符的所有排列,你可以以任意顺序返回这个字符串数组。
例如输入字符串ABC,则输出由字符A,B,C所能排列出来的所有字符串ABC,ACB,BAC,BCA,CBA和CAB。

 示例1

输入:"ab"
返回值:["ab","ba"]
说明:返回["ba","ab"]也是正确的 

2.2 解题思路

上图中基于三叉树的一个穷举过程, 然后再剪枝, 就得到了符合要求的排列组合.

于是这道题的全排列问题, 就可以看做如下三叉树型状态:

基本思路:

  1. 分别以 a, b, c 作为排列组合的起始字符, 然后 bc, ac, ab 再分别排列组合 (循环 + 递归)
  2. 这三次循环, 每排列组合完其中一种情况, 就需要进行回溯, 然后继续下一次排列组合.
  3. 注意每次准备将待选结果添加进结果集之前, 需要做去重处理, 以免出现类似于 "aa" 排列组合两次的情况.

2.3 代码实现

    public void swap(char[] str, int start, int i) {
        char tmp = str[start];
        str[start] = str[i];
        str[i] = tmp;
    }
    public boolean isExist(ArrayList<String> result, char[] str) {
        return result.contains(String.valueOf(str));
    }
    public void PermutationHelper(char[] str, int start, ArrayList<String> result) {
        if (start == str.length - 1) {
            // 去重
            if (!isExist(result, str)) {
                result.add(new String(str));
            }
            return;
        }
        for (int i = start; i < str.length; i++) {
            swap(str, start, i); // 以 i 对应的字符作为开始
            PermutationHelper(str, start + 1, result); // [i+ 1, str.length- 1] 排列组合
            swap(str, start, i); // 回溯
        }
    }
    public ArrayList<String> Permutation(String str) {
        ArrayList<String> list =  new ArrayList<>();
        if (str == null) {
            return list;
        }
        char[] ch = str.toCharArray();
        PermutationHelper(ch, 0, list);
        return list;
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Master_hl

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值