Advertisement
KeepCoding

Trees-AllPathsWithGivenSum-RecursiveVariant

Mar 25th, 2020
540
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 5.74 KB | None | 0 0
  1. package implementations;
  2.  
  3. import interfaces.AbstractTree;
  4.  
  5. import java.util.ArrayDeque;
  6. import java.util.ArrayList;
  7. import java.util.List;
  8. import java.util.stream.Collectors;
  9.  
  10. public class Tree<E> implements AbstractTree<E> {
  11.     private E key;
  12.     private Tree<E> parent;
  13.     private List<Tree<E>> children;
  14.  
  15.     public Tree(E key) {
  16.         this.key = key;
  17.         children = new ArrayList<>();
  18.     }
  19.  
  20.     @Override
  21.     public void setParent(Tree<E> parent) {
  22.         this.parent = parent;
  23.     }
  24.  
  25.     @Override
  26.     public void addChild(Tree<E> child) {
  27.         children.add(child);
  28.     }
  29.  
  30.     @Override
  31.     public Tree<E> getParent() {
  32.         return parent;
  33.     }
  34.  
  35.     @Override
  36.     public E getKey() {
  37.         return key;
  38.     }
  39.  
  40.     @Override
  41.     public String getAsString() {
  42.         StringBuilder result = new StringBuilder();
  43.         getAsString(this, 0, result);
  44.         return result.substring(0, result.lastIndexOf(System.lineSeparator()));
  45.     }
  46.  
  47.     @Override
  48.     public List<E> getLeafKeys() {
  49.         return getLeafs().stream().map(l -> l.key).collect(Collectors.toList());
  50.     }
  51.  
  52.     @Override
  53.     public List<E> getMiddleKeys() {
  54.         return getAllTreesDFS().stream()
  55.                 .filter(t -> t.hasParentAndAnyChildren())
  56.                 .map(t -> t.key)
  57.                 .collect(Collectors.toList());
  58.     }
  59.  
  60.     @Override
  61.     public Tree<E> getDeepestLeftmostNode() {
  62.         int deepestLevel = -1;
  63.  
  64.         List<Tree<E>> leafs = getLeafs();
  65.         Tree<E> result = null;
  66.  
  67.         for (Tree<E> currentLeaf : leafs) {
  68.             int currentLeafLevel = currentLeaf.getLevel();
  69.             if (currentLeafLevel > deepestLevel) {
  70.                 deepestLevel = currentLeafLevel;
  71.                 result = currentLeaf;
  72.             }
  73.         }
  74.  
  75.         return result;
  76.     }
  77.  
  78.     @Override
  79.     public List<E> getLongestPath() {
  80.         Tree<E> deepestLeftmostNode = getDeepestLeftmostNode();
  81.         return deepestLeftmostNode.getPath();
  82.     }
  83.  
  84.     @Override
  85.     public List<List<E>> pathsWithGivenSum(int sum) {
  86.         List<List<E>> listOfSumPaths = new ArrayList<>();
  87.         pathsWithGivenSum(this, (Integer)this.key, sum, listOfSumPaths);
  88.         return listOfSumPaths;
  89.     }
  90.  
  91.     // Not optimal solution. Sums are calculated multiple times.
  92.     // Solution would be for each tree to have a field to hold the value of sum
  93.     // and each time a new tree is created, all of it's parents would have to increase their sums
  94.     // with the value of the new tree. But that would slow down a more important method - adding a new tree.
  95.     @Override
  96.     public List<Tree<E>> subTreesWithGivenSum(int sum) {
  97.         List<Tree<E>> allTrees = getAllTreesDFS();
  98.  
  99.         return allTrees.stream()
  100.                 .filter(t -> t.getSum() == sum)
  101.                 .collect(Collectors.toList());
  102.     }
  103.  
  104.     /**
  105.      *
  106.      * @return sum of current tree and all subtrees
  107.      */
  108.     private int getSum() {
  109.         return getAllTreesDFS().stream()
  110.                 .map(t -> (Integer)t.key)
  111.                 .reduce(0, (accumulator, element) -> accumulator += element);
  112.     }
  113.  
  114.     private void getAsString(Tree<E> currentTree, int indentation, StringBuilder stringBuilder) {
  115.         stringBuilder.append(getKeyWithIndentation(currentTree.key, indentation)).append(System.lineSeparator());
  116.  
  117.         for (Tree<E> childTree : currentTree.children) {
  118.             getAsString(childTree, indentation + 2, stringBuilder);
  119.         }
  120.     }
  121.  
  122.     private String getKeyWithIndentation(E key, int indentation) {
  123.         StringBuilder result = new StringBuilder();
  124.         for (int i = 0; i < indentation; i++) {
  125.             result.append(" ");
  126.         }
  127.  
  128.         result.append(key.toString());
  129.         return result.toString();
  130.     }
  131.  
  132.     /**
  133.      *
  134.      * @return current tree and subtrees in pre-order (root -> left -> right).
  135.      */
  136.     private List<Tree<E>> getAllTreesDFS() {
  137.         List<Tree<E>> result = new ArrayList<>();
  138.         getAllTreesDFS(this, result);
  139.         return result;
  140.     }
  141.  
  142.     private void getAllTreesDFS(Tree<E> currentTree, List<Tree<E>> allTrees) {
  143.         allTrees.add(currentTree);
  144.  
  145.         for (Tree<E> child : currentTree.children) {
  146.             getAllTreesDFS(child, allTrees);
  147.         }
  148.     }
  149.  
  150.     private List<Tree<E>> getLeafs() {
  151.         return getAllTreesDFS().stream().filter(t -> t.children.isEmpty()).collect(Collectors.toList());
  152.     }
  153.  
  154.     /**
  155.      *
  156.      * @return level of tree. A root (no parents) will return level 1.
  157.      */
  158.     private int getLevel() {
  159.         Tree<E> currentTree = this;
  160.         int levelCounter = 0;
  161.  
  162.         while (currentTree != null) {
  163.             currentTree = currentTree.parent;
  164.             levelCounter++;
  165.         }
  166.  
  167.         return levelCounter;
  168.     }
  169.  
  170.     /**
  171.      *
  172.      * @return list of tree keys from root to current tree inclusive
  173.      */
  174.     private List<E> getPath() {
  175.         ArrayDeque<E> stack = new ArrayDeque<>();
  176.         Tree<E> currentTree = this;
  177.  
  178.         while (currentTree != null) {
  179.             stack.push(currentTree.key);
  180.             currentTree = currentTree.parent;
  181.         }
  182.  
  183.         return new ArrayList<>(stack);
  184.     }
  185.  
  186.     private void pathsWithGivenSum(Tree<E> currentTree, int accumulatedSum, int searchedSum, List<List<E>> listOfSumPaths) {
  187.         if (currentTree.children.isEmpty() && accumulatedSum == searchedSum) {
  188.             listOfSumPaths.add(currentTree.getPath());
  189.         }
  190.  
  191.         for (Tree<E> child : currentTree.children) {
  192.             pathsWithGivenSum(child, accumulatedSum + (Integer)child.key, searchedSum, listOfSumPaths);
  193.         }
  194.     }
  195.  
  196.     private boolean hasParentAndAnyChildren() {
  197.         return this.parent != null && !this.children.isEmpty();
  198.     }
  199. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement