1、二叉搜索树的后序遍历序列
1.1 题目描述:
输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历结果。如果是则返回 true,否则返回 false。假设输入的数组的任意两个数字都互不相同。
1.2 题解
1.2.1 递归
后序遍历定义: [ 左子树 | 右子树 | 根节点 ] ,即遍历顺序为 “左、右、根” 。
二叉搜索树定义: 左子树中所有节点的值 << 根节点的值;右子树中所有节点的值 >> 根节点的值;其左、右子树也分别为二叉搜索树。
public boolean verifyPostorder(int[] postorder) {
return recur(postorder, 0, postorder.length - 1);
}
boolean recur(int[] postorder, int i, int j) {
if(i >= j) return true;
int p = i;
while(postorder[p] < postorder[j]) p++;//找到左子树
int m = p;
while(postorder[p] > postorder[j]) p++;//找到右子树
//p==j 只有左子树,正确
// 继续进行做左右子树的判断
return p == j && recur(postorder, i, m - 1) && recur(postorder, m, j - 1);
}
1.2.2 辅助单调栈
public boolean verifyPostorder(int[] postorder) {
int root = Integer.MAX_VALUE;
Stack<Integer> stack = new Stack<>();
for(int i = postorder.length - 1; i >= 0; i--) {
if(postorder[i]>root)
return false;
while(!stack.isEmpty() &&postorder[i]<stack.peek())
{
root=stack.pop();
}
stack.add(postorder[i]);
}
return true;
}
2、二叉树中和为某一值的路径
2.1 题目描述:
输入一棵二叉树和一个整数,打印出二叉树中节点值的和为输入整数的所有路径。从树的根节点开始往下一直到叶节点所经过的节点形成一条路径。
2.2 题解
2.2.1 递归
后序遍历定义: [ 左子树 | 右子树 | 根节点 ] ,即遍历顺序为 “左、右、根” 。
二叉搜索树定义: 左子树中所有节点的值 << 根节点的值;右子树中所有节点的值 >> 根节点的值;其左、右子树也分别为二叉搜索树。
public List<List<Integer>> pathSum(TreeNode root, int sum) {
List<List<Integer>> res = new ArrayList<>();
List<Integer> list = new ArrayList<>();
help(res, list,root, sum);
return res;
}
public void help(List<List<Integer>> res, List<Integer> list,TreeNode node, int sum) {
if (node==null)
return;
sum=sum-node.val;
list.add(node.val);
if(sum==0&&node.left==null&&node.right==null)
res.add(new ArrayList<>(list));
help(res,list,node.left,sum);
help(res,list,node.right,sum);
list.remove(list.size()-1);
}
3、复杂链表的复制
3.1 题目描述:
请实现 copyRandomList 函数,复制一个复杂链表。在复杂链表中,每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意节点或者 null。
3.2 题解
3.2.1
public Node copyRandomList(Node head) {
if (head == null) return head;
//在每个Node后面新建一个Node做自己的copy
copy(head);
// 先处理random域,因为需要用到next域
handleRandom(head);
// 需要暂存copyHead,因为后续会改变next域
Node res = head.next;
handleNext(head);
return res;
}
private void copy(Node head){
while (head != null) {
Node tmp = head.next;
Node copy = new Node(head.val);
head.next = copy;
copy.next = tmp;
head = tmp;
}
}
private void handleRandom(Node head){
while (head != null) {
// 把copy节点的random也指向copy节点
Node copy = head.next;
// 注意:random可能指向null,此时不能指向其next结点
if (head.random != null) {
copy.random = head.random.next;
}
head = copy.next;
}
}
// 处理next域 , 这里需要把源和copy节点一起处理,因为next结点是相关的。
// 若单处理一者,循环后,另一个就没办法找到属自己类的结点了。
// 两者处理相同: curNode.next = curNode.next.next
// 源 -> copy -> {源 -> copy}+ -> null
private void handleNext(Node cur){
// 循环条件无需为: cur!=null
while (true) {
// 处理最后一个 源结点,指回null
// 而在这之前,cur都不可能为空
if (cur.next != null && cur.next.next == null) {
cur.next = null;
break;
}
Node tmp = cur.next;
cur.next = tmp.next;
cur = tmp;
}
}
3.2.2 利用HashMap
public Node copyRandomList(Node head) {
HashMap<Node,Node> map = new HashMap<>(); //创建HashMap集合
Node cur=head;
//复制结点值
while(cur!=null){
//存储put:<key,value1>
map.put(cur,new Node(cur.val)); //顺序遍历,存储老结点和新结点(先存储新创建的结点值)
cur=cur.next;
}
//复制结点指向
cur = head;
while(cur!=null){
//得到get:<key>.value2,3
map.get(cur).next = map.get(cur.next); //新结点next指向同旧结点的next指向
map.get(cur).random = map.get(cur.random); //新结点random指向同旧结点的random指向
cur = cur.next;
}
//返回复制的链表
return map.get(head);
}