辛星Java树算法第十四篇:二叉树上路径和为某个值的所有路径

这是一道非常经典的题目,在《剑指offer》中也有收录,而且在各大博客中也有提及。
路径和的使用还是非常广泛的,因为操作简单,灵活性强。

首先我们要给出这种树的定义:

package com.mengzhidu.teach.algorithm.tree.demo;

/**
 * Created by xinxing on 2019/4/11
 */
public class NumTreeNode {
    private int value;

    private NumTreeNode left;

    private NumTreeNode right;

    public NumTreeNode(int value, NumTreeNode left, NumTreeNode right) {
        this.value = value;
        this.left = left;
        this.right = right;
    }

    public int getValue() {
        return value;
    }

    public void setValue(int value) {
        this.value = value;
    }

    public NumTreeNode getLeft() {
        return left;
    }

    public void setLeft(NumTreeNode left) {
        this.left = left;
    }

    public NumTreeNode getRight() {
        return right;
    }

    public void setRight(NumTreeNode right) {
        this.right = right;
    }
}

然后我们为了方便后面的操作,我们给一个助手方法:

package com.mengzhidu.teach.algorithm.tree.demo;

/**
 * Created by xinxing on 2019/4/12
 */
public class NumTreeNodeHelper {

    /**
     *          22
     *         /  \
     *        0    3
     *           /  \
     *          -3   4
     *              / \
     *            -7  8
     * @return
     */
    public static NumTreeNode getNumberTreeNode() {
        NumTreeNode aNode = new NumTreeNode(-7, null, null);
        NumTreeNode bNode = new NumTreeNode(8, null, null);
        NumTreeNode cNode = new NumTreeNode(4, aNode, bNode);
        NumTreeNode dNode = new NumTreeNode(-3, null, null);
        NumTreeNode eNode = new NumTreeNode(3, dNode, cNode);
        NumTreeNode fNode = new NumTreeNode(0, null, null);
        NumTreeNode root = new NumTreeNode(22, fNode, eNode);
        return root;
    }
}

我们这里给出的思路依然是通过递归的方式给出,其实大多数人见到这个题的第一个思路,就是它应该类似于前序遍历的方式来解决。

一般来说常规的思路是这样的:

package com.mengzhidu.teach.algorithm.tree.demo.path;

import com.mengzhidu.teach.algorithm.tree.demo.NumTreeNode;
import com.mengzhidu.teach.algorithm.tree.demo.NumTreeNodeHelper;

import java.util.ArrayList;
import java.util.List;

/**
 * 获取所有的路径节点和列表
 * 它在第一种方式上优化了一下空间开销
 */
public class PathSumDemo2 {

    private static final List<NumTreeNode> currentList = new ArrayList<>();
    private static final List<List<NumTreeNode>> allList = new ArrayList<>();

    public static void main(String[] args) {
        NumTreeNode node = NumTreeNodeHelper.getNumberTreeNode();
        getPathSumList(node, 22);
        System.out.println("所有的路径和为22的链路为:");
        for (List<NumTreeNode> list : allList) {
            for (NumTreeNode item : list) {
                System.out.print(item.getValue() + " ");
            }
            System.out.println();
        }
    }

    private static void getPathSumList(NumTreeNode node, int sum) {
        if (node == null) {
            return;
        }

        currentList.add(node);
        if (node.getValue() == sum) {
            allList.add(new ArrayList<>(currentList));
        }

        if (node.getLeft() != null) {
            getPathSumList(node.getLeft(), sum - node.getValue());
        }

        if (node.getRight() != null) {
            getPathSumList(node.getRight(), sum - node.getValue());
        }

        currentList.remove(currentList.size() - 1);
    }

}

这里需要它在递归的时候,在它向上返回的时候,它是需要清理掉当前节点的数据的,这样会节省空间。

还有一种稍显笨拙的递归方法,它占用的空间更高,但是它的方法还是比较原始的,这里也给出来吧:

package com.mengzhidu.teach.algorithm.tree.demo.path;

import com.mengzhidu.teach.algorithm.tree.demo.NumTreeNode;
import com.mengzhidu.teach.algorithm.tree.demo.NumTreeNodeHelper;

import java.util.ArrayList;
import java.util.List;

/**
 * 获取所有的路径和的节点列表
 * 这里最大的问题就是每次访问一个新的节点的时候就必须得创建一个新的链表
 * 占用空间巨大,不推荐,但是它反映了一个原始的思路
 */
public class PathSumDemo1 {

    public static void main(String[] args) {
        NumTreeNode root = NumTreeNodeHelper.getNumberTreeNode();
        List<List<NumTreeNode>> list = new ArrayList<>();
        getPathSumList(root, 22, new ArrayList<NumTreeNode>(), list);
        System.out.println("所有的路径和为22的链路为:");
        for (List<NumTreeNode> item : list) {
            for (NumTreeNode node : item) {
                System.out.print(node.getValue() + " ");
            }
            System.out.println();
        }
    }


    private static void getPathSumList(NumTreeNode node, int sum, List<NumTreeNode> currentResult,
                                                          List<List<NumTreeNode>> allResult) {
        if (node == null) {
            return;
        }

        currentResult.add(node);

        if (node.getValue() == sum) {
            allResult.add(currentResult);
        }

        if (node.getLeft() != null) {
            List<NumTreeNode> leftList = new ArrayList<>();
            leftList.addAll(currentResult);
            getPathSumList(node.getLeft(), sum - node.getValue(), leftList, allResult);
        }

        if (node.getRight() != null) {
            ArrayList<NumTreeNode> rightList = new ArrayList<>();
            rightList.addAll(currentResult);
            getPathSumList(node.getRight(), sum - node.getValue(), rightList, allResult);
        }
    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值