As there are several smart solutions posted already, my solution is not the most optimal. I just want to share some thoughts.

dfs() adds the leaf nodes to a temporary list, removes the leaf nofes, and returns the new root. One drawback of this solution is that it modifies the original tree.

```
public List<List<Integer>> findLeaves(TreeNode root) {
List<List<Integer>> res = new LinkedList<>();
while (root != null) {
List<Integer> temp = new LinkedList<>();
root = dfs(root, temp);
res.add(temp);
}
return res;
}
public TreeNode dfs(TreeNode root, List<Integer> temp) {
if (root == null) {
return root;
}
if (root.left == null && root.right == null) {
temp.add(root.val);
return null;
}
root.left = dfs(root.left, temp);
root.right = dfs(root.right, temp);
return root;
}
```