Bottom up approach, easy to understand - 99% faster
\n\n    List<TreeNode> result = new ArrayList<>();\n    Set<Integer> ito_delete = new HashSet<>();\n\n    public List<TreeNode> delNodes(TreeNode root, int[] to
```\n\n    List<TreeNode> result = new ArrayList<>();\n    Set<Integer> ito_delete = new HashSet<>();\n\n    public List<TreeNode> delNodes(TreeNode root, int[] to_delete) {\n\n        for (int i : to_delete)\n            ito_delete.add(i);\n\n        if (root != null && !ito_delete.contains(root.val))\n            result.add(root);\n\n        delNodes(root);\n        return result;\n    }\n\n\n    public void delNodes(TreeNode root) {\n        if (root == null)\n            return;\n        //botton up approach\n        //post order traversal\n        delNodes(root.left);\n        delNodes(root.right);\n\n        //if root\'s left isn\'t null and left\'s val is in the index make it null\n        //will handle such case\n        //     1\n        //    /\n        //   2\n        //  / \\\n        // 4   3\n        //to_delete [2,3]\n        if (root.left != null && ito_delete.contains(root.left.val))\n            root.left = null;\n\n        //if root\'s right isn\'t null and right\'s val is in the index make it null\n        if (root.right != null && ito_delete.contains(root.right.val))\n            root.right = null;\n\n        //now visiting the node from bottom, we\'ve already visited all of its children before\n        if (ito_delete.contains(root.val)) {\n            //if left isn\'t null, add it [we cleaned it above in case it was in to_deleted]\n            if (root.left != null)\n                result.add(root.left);\n\n            //if right isn\'t null, add it [we cleaned it above in case it was in to_deleted]\n            if (root.right != null)\n                result.add(root.right);\n\n        }\n\n\n    }\n\n\n```\n\nFor local unit testing and more explanation, please visit my github repo https://github.com/msolimans/algorithms
[]