保留N叉树的指定路径(from 字节跳动)

一、问题

题目要求:保留包含target字符的路径,去掉不包含target的路径

举例,比如有两条路径,f->i->r->e,h->i->r->e,保留包含f的路径,那么h->i->r->e就会被清理掉

输出:返回结果是当前树的根节点

树的结构如下:

class TreeNode {

    char val;
    TreeNode[] children;

    public TreeNode(char val) {
        this.val = val;
        children = new TreeNode[26];
    }

}

二、解决方法:

(1)判断当前节点是否等于target,等于,则后续节点都不会去掉,因此直接return true;

(2)如果当前节点的子节点都返回false,且当前节点不等于target,那么包含该节点在内的所有节点都要去掉;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class Main {

    public static void main(String[] args) {
        /**
         * 题目要求:保留包含target字符的路径,去掉不包含target的路径
         * 举例,比如有两条路径,f->i->r->e,h->i->r->e,保留包含f的路径,那么h->i->r->e就会被清理掉
         * @return 返回结果是当前树的根节点
         */
        TreeNode root = initTree();
        System.out.println("进行处理前");
        showRoute(root);
        System.out.println("进行处理后");
        findRouteWithTargetDfs(root);
        showRoute(root);
    }

    static char target = 't';   // 保留包含t字符的路径
    
    // 核心代码
    private static boolean findRouteWithTargetDfs(TreeNode root) {
        if(root == null) {
            return false;
        }
        // 包含了target,后面的都保留
        if(root.val == target) {
            return true;
        }
        boolean hasTarget = false;   // 子树中只要有一个包含target,那么当前节点就不能被删掉
        for(int i = 0; i < root.children.length; i++) {
            TreeNode child = root.children[i];
            boolean childHasTarget = findRouteWithTargetDfs(child);
            if(childHasTarget) {
                hasTarget = true;
            } else {
                // 因为以当前子节点为首的树不包含target信息,去掉这一部分树
                root.children[i] = null;
            }
        }

        return hasTarget;
    }

    /**
     * 以下内容不需要关注了,只是单纯初始化基本信息,显示当前所有的路径
     */

    // 这里只是一个基础数据的初始化,没有任何含义
    private static TreeNode initTree() {
        String[] arr = new String[]{"it", "is", "a", "test"};
        TreeNode root = new TreeNode('X');
        for(String a : arr) {
            TreeNode p = root;
            for(char c : a.toCharArray()) {
                if(p.children[c - 'a'] == null) {
                    p.children[c - 'a'] = new TreeNode(c);
                }
                p = p.children[c - 'a'];
            }
        }
        return root;
    }

    // 展示当前所有的路径,用于验证,和代码本身无关
    private static void showRoute(TreeNode root) {
        Set<String> ans = new HashSet<>();
        searchRouteDfs(root, new ArrayList<>(), ans);
        System.out.println(ans);
    }

    // 一个简单的dfs方法,用于找到所有的路径
    private static void searchRouteDfs(TreeNode root,
                                       List<Character> routList, Set<String> allRoute) {


        if(isLeaf(root)) {
            routList.add(root.val);
            allRoute.add(transToStr(routList));
            routList.remove(routList.size() - 1);
            return ;
        }

        routList.add(root.val);

        for(TreeNode child : root.children) {
            if(child == null) continue;;
            searchRouteDfs(child, routList, allRoute);
        }

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

    private static boolean isLeaf(TreeNode root) {
        if(root == null) {
            return false;
        }
        int nullChildCount = 0;
        for(int i = 0; i < root.children.length; i++) {
            if(root.children[i] == null)nullChildCount++;
        }
        return nullChildCount == root.children.length;
    }

    private static String transToStr(List<Character> routList) {
        StringBuilder strb = new StringBuilder();
        for(int i = 0; i < routList.size(); i++) {
            char c = routList.get(i);
            strb.append(c);
            if(i != routList.size() - 1) {
                strb.append("->");
            }
        }
        return strb.toString();
    }

}

class TreeNode {

    char val;
    TreeNode[] children;

    public TreeNode(char val) {
        this.val = val;
        children = new TreeNode[26];
    }

}

三、说明

1、本题没有要求bugfree,事实上bugfree确实比较难。

2、原题中,TreeNode里不是字符型的val,而是一个String,并且要求判断包含前缀即可,事实上,这部分使用s.startsWith()即可,但从我的角度来看,这样的设定有失偏颇,有画蛇添足之嫌,并没有影响到考察内容(我认为此题的考察还是树结构的遍历),因此,我对题目做了修改,

(1)改为了更简单的Character类型;

(2)增加了不可删除的root节点(一个固定的大写X),减少特殊场景的适配;

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值