private TreeNode buildTree(
      int[] inorder, int inStart, int inEnd, int[] postorder, int postStart, int postEnd) {
    // base case
    if (inStart > inEnd) {
      return null;
    }
    if (inStart == inEnd) {
      return new TreeNode(inorder[inStart]);
    }

    // recursive case
    int rootVal = postorder[postEnd];
    // find root value in inorder array
    int rootIndexInInorder = -1;
    for (int i = inStart; i <= inEnd; i++) {
      if (inorder[i] == rootVal) {
        rootIndexInInorder = i;
        break;
      }
    }
    TreeNode root = new TreeNode(rootVal);
    int leftEnd = rootIndexInInorder - 1 - inStart + postStart;
    root.left = buildTree(inorder, inStart, rootIndexInInorder - 1, postorder, postStart, leftEnd);
    root.right =
        buildTree(inorder, rootIndexInInorder + 1, inEnd, postorder, leftEnd + 1, postEnd - 1);

    return root;
  }
 //       3
 //         \
 //          20
 //         /
 //        15
 @Test
 public void Test3() {
   TreeNode t1 = new TreeNode(3);
   TreeNode t3 = new TreeNode(20);
   TreeNode t4 = new TreeNode(15);
   TreeNode.connect(t1, null, t3);
   TreeNode.connect(t3, t4, null);
   TreeNode root = t1;
   List<List<Integer>> actual = solution.levelOrder(root);
   List<List<Integer>> expected = new ArrayList<>();
   expected.add(Arrays.asList(3));
   expected.add(Arrays.asList(20));
   expected.add(Arrays.asList(15));
   assertEquals(expected, actual);
 }