code: private BinaryTree getViterbiTree(int start, int end, int rootSymbol) {
          ChartCell cell = chart[start][end];
          BackPointer bp = cell.getBp(rootSymbol);
          if (bp == null) {
              return null;
          }
          
          BinaryTree leftChild;
          BinaryTree rightChild;
          if (bp.r.isLexical()) {
              String lcSymbolStr = grammar.getLexAlphabet().lookupObject(bp.r.getLeftChild());
              leftChild = new BinaryTree(lcSymbolStr, start, end, null, null, true);
              rightChild = null;
          } else if (bp.r.isUnary()) {
              leftChild = getViterbiTree(start, bp.mid, bp.r.getLeftChild());
              rightChild = null;
          } else {
              leftChild = getViterbiTree(start, bp.mid, bp.r.getLeftChild());
              rightChild = getViterbiTree(bp.mid, end, bp.r.getRightChild());
          }
          
          String rootSymbolStr = grammar.getNtAlphabet().lookupObject(rootSymbol);
          return new BinaryTree(rootSymbolStr, start, end, leftChild, rightChild, false);
      }
docs: Gets the highest probability tree with the span (start, end) and the root symbol rootSymbol.
  
  @param start The start of the span of the requested tree.
  @param end The end of the span of the requested tree.
  @param rootSymbol The symbol of the root of the requested tree.
  @return The highest probability tree or null if no parse exists.