LeetCode上与树相关的问题

前言

没想到大三依然课业繁重,再加上一些琐事缠身,以及自身的惰性,不少计划都是心有余力不足,但又不愿这么混下去,近来回顾了一下自己在学习算法技能树上的加点,发现一些基础算法与经典算法实在是有那么点囫囵吞枣,所以有个刷leetcode的打算,一是为了温故知新,二是为了熟悉Java或Python,三是为了保持编程手感,四是为以后工作做个铺垫?

目标大概是有生之年内用Java/Python/C++/C刷一遍leetcode上有趣的题。【原则上first Java,second Python,third C/C++】

而具体计划呢则是没有的,印象中上了大学后,只要说出来或写出来的计划都会被各种不可抗力因素打断(比如本博客就有很多未完待续的坑。。),所以能刷一题是一题,能学一点是一点,博客尽量更新,这学期结束估计就主要忙考研的事去了,而这两个月也是有各种考试报告要腾出手去处理,所以。。这TM又是一个大坑!


Easy

Problem 100. Same Tree

题意

判断两棵树是否相同.

思路

见代码.

代码

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {
    public boolean isSameTree(TreeNode p, TreeNode q) {
        if (p == null && q == null)
            return true;
        if (p == null && q != null)
            return false;
        if (p != null && q == null)
            return false;
        if (p != null && q != null && p.val == q.val)
            return isSameTree(p.left, q.left) && isSameTree(p.right, q.right);
        return false;
    }
}

Problem 101. Symmetric Tree

题意

判断一颗二叉树是否镜像对称

思路

递归写起来要简洁一些..

代码

// recursive
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {
    public boolean mySymmetric(TreeNode leftNode, TreeNode rightNode) {
        if (leftNode != null && rightNode != null && leftNode.val == rightNode.val)
            return mySymmetric(leftNode.left, rightNode.right) && mySymmetric(leftNode.right, rightNode.left);
        else if (leftNode == null && rightNode == null)
            return true;
        else return false;
    }
    public boolean isSymmetric(TreeNode root) {
        if (root == null) return true;
        else return mySymmetric(root.left, root.right);
    }
}
// iterative
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {
    public boolean isSymmetric(TreeNode root) {
        Queue q = new LinkedList();
        q.add(root);
        q.add(root);
        while (!q.isEmpty()) {
            TreeNode leftNode = q.poll();
            TreeNode rightNode = q.poll();
            if (leftNode == null && rightNode == null) continue;
            else if (leftNode == null || rightNode == null) return false;
            else if (leftNode.val != rightNode.val) return false;
            q.add(leftNode.left);
            q.add(rightNode.right);
            q.add(leftNode.right);
            q.add(rightNode.left);
        }
        return true;
    }
}

Problem 102. Binary Tree Level Order Traversal

题意

输出二叉树每一层的元素

思路

思路没什么难的,就是语法上纠结了一下。。
关于List的各种方法以及实现可以参考这个:
ArrayList方法的实现
List的接口与使用示例

代码

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {

    public List> treeList = new ArrayList>();

    public void traversal(TreeNode root, int depth) {
        if (root == null) return;
        if(treeList.size() == depth) treeList.add(new ArrayList());
        treeList.get(depth).add(root.val);
        traversal(root.left, depth + 1);
        traversal(root.right, depth + 1);
    }

    public List> levelOrder(TreeNode root) {
        traversal(root, 0);
        return treeList;
    }
}

Problem 107. Binary Tree Level Order Traversal II

题意

从一颗二叉树底部开始输出每一层节点的值

思路

102的小小进阶,没啥难点,如果是cpp或者python的话可以直接用reverse函数就行,不知道为啥java的Collections.reverse()不行。。所以直接改的list插入位置。
update:Collections.reverse()【无返回值】也可以

代码

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {

    public List> treeList = new ArrayList>();

    public void traversal(TreeNode root, int depth) {
        if (root == null) return;
        if(treeList.size() == depth) treeList.add(0, new ArrayList());
        treeList.get(treeList.size() - depth - 1).add(root.val);
        traversal(root.left, depth + 1);
        traversal(root.right, depth + 1);
    }

    public List> levelOrderBottom(TreeNode root) {
        traversal(root, 0);
//        Collections.reverse(treeList);
        return treeList;
    }
}

Problem 110. Balanced Binary Tree

题意

判断一颗二叉树是否平衡(左右子树高度相差不超过1)

思路

求下高度就ok。

代码

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {
    public int getDepth(TreeNode root) {
        if (root == null) 
            return 0;
        else return Math.max(getDepth(root.left), getDepth(root.right)) + 1;
    }

    public boolean isBalanced(TreeNode root) {
        if (root == null)
            return true;
        int leftDepth = getDepth(root.left);
        int rightDepth = getDepth(root.right);
        int diff = Math.abs(leftDepth - rightDepth);
        if (diff > 1) return false;
        else return isBalanced(root.left) && isBalanced(root.right);
    }
}

Problem 111. Minimum Depth of Binary Tree

题意

求一颗二叉树根节点到最近叶子节点的最短路径要经过多少个节点。

思路

和求高度的思路比较相似。

代码

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {
    public int minDepth(TreeNode root) {
        if (root == null)
            return 0;
        if (root.left == null && root.right == null)
            return 1;
        else if (root.left != null && root.right == null)
            return minDepth(root.left) + 1;
        else if (root.left == null && root.right != null)
            return minDepth(root.right) + 1;
        else return Math.min(minDepth(root.left), minDepth(root.right)) + 1;
    }
}

Problem 112. Path Sum

题意

输入一颗二叉树与一个整数sum,求是否有一条根节点到叶节点的路径,使得路径经过的节点值之和恰好等于sum。

思路

普通的dfs。

代码

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {
    public boolean hasPathSum(TreeNode root, int sum) {
        if (root == null) return false;
        else if (root.left == null && root.right == null && sum == root.val) 
            return true;
        else return hasPathSum(root.left, sum - root.val) || hasPathSum(root.right, sum - root.val);
    }
}

Problem 226. Invert Binary Tree

题意

just invert a binary tree.
ps. 传说中干掉Max Howell的Google面试题233

思路

依然普通的dfs…

代码

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {
    public TreeNode invertTree(TreeNode root) {
        if (root == null)
            return root;
        TreeNode right = invertTree(root.right);
        TreeNode left = invertTree(root.left);
        root.left = right;
        root.right = left;
        return root;
    }
}

Problem 235. Lowest Common Ancestor of a Binary Search Tree

题意

输入一棵BST,以及两个节点p,q,求p与q的LCA。

思路

由于BST的特性(左小右大),p与q的LCA节点的值一定处于p与q的值之间,即

pvalLCAvalqval

所以从root节点开始dfs,直到找到符合这一条件的节点即为LCA。

代码

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if ((root.val - p.val) * (root.val - q.val) <= 0)
            return root;
        else if (root.val > q.val)
            return lowestCommonAncestor(root.left, p, q);
        else
            return lowestCommonAncestor(root.right, p, q);
    }
}

Problem 257. Binary Tree Paths

题意

输入一棵二叉树,输出所有根节点到叶节点的路径

思路

对java不是太熟悉,所以是用dfs来写。如果用Python的话bfs实现也挺简单的。

代码

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {
    public List pathList = new ArrayList();

    public void getPath(TreeNode root, String path) {
        if (root == null) return;
        if (root.left == null && root.right == null) {
            pathList.add(path + Integer.toString(root.val));
            return;
        }

        getPath(root.left, path + Integer.toString(root.val) + "->");
        getPath(root.right, path + Integer.toString(root.val) + "->");
    }

    public List binaryTreePaths(TreeNode root) {
        if (root == null)
            return pathList;
        getPath(root, "");
        return pathList;
    }
}

Medium

Problem 94. Binary Tree Inorder Traversal

题意

中序遍历一颗二叉树(要求非递归实现)

思路

迭代法,参考wiki上的伪代码:

iterativeInorder(node)
  parentStack = empty stack
  while (not parentStack.isEmpty() or node ≠ null)
    if (node ≠ null)
      parentStack.push(node)
      node = node.left
    else
      node = parentStack.pop()
      visit(node)
      node = node.right

代码

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {
    public List inorderTraversal(TreeNode root) {
        List res = new ArrayList();
        if (root == null) return res;
        Stack s = new Stack();
        while (root != null || !s.empty()) {
            while (root != null) {
                s.push(root);
                root = root.left;
            }
            root = s.pop();
            res.add(root.val);
            root = root.right;
        }
        return res;
    }
}

Problem 96. Unique Binary Search Trees

题意

输入一个数n,输出[1,..,n]能组成多少棵不同的BST.

思路

实际上多推几项就可以发现答案是Catalan数:

Cn=1n+1(2nn)=(2n)!(n+1)! n!

这里说下DP的思路:
设num[i]为[1,..,n]能组成的不同BST数目,num[n]就是我们要求的答案。
显然,num[0] = num[1] = 1;
设BST的根节点为j,1 <= j <= n,那么有num[j-1]种左子树与num[i-j]种有子树,故得到如下递推式:
numi=j=1inumj1numij

代码

//DP
public class Solution {
    public int numTrees(int n) {
        int num[] = new int[n + 1];
        num[0] = num[1] = 1;
        for (int i = 2; i <= n; i++) {
            int sum = 0;
            for (int j = 1; j <= i; j++) {
                sum += num[j - 1] * num[i - j];
            }
            num[i] = sum;
        }
        return num[n];
    }
}

Problem 95. Unique Binary Search Trees II

题意

输入一个数n,输出[1,..,n]能组成的所有BST.

思路

思路和上一题差不多,但由于这次需要返回的是TreeNode的List,所以需要在子树生成器上花点功夫,可以先确定根节点,然后递归生成左右子树。

代码

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {

    public List generateSubTrees(int start, int end) {
        List res = new ArrayList();
        if (start > end) {
            res.add(null);
            return res;
        }
        for (int val = start; val <= end; val++) {
            for (TreeNode left: generateSubTrees(start, val - 1)) {
                for (TreeNode right: generateSubTrees(val + 1, end)) {
                    TreeNode root = new TreeNode(val);
                    root.left = left;
                    root.right = right;
                    res.add(root);
                }
            }
        }
        return res;
    }

    public List generateTrees(int n) {
        if (n == 0) return new ArrayList();
        return generateSubTrees(1, n);
    }
}

Problem 98. Validate Binary Search Tree

题意

判断一颗树是否是BST.

思路

照着定义A过去就行了。。
update. 发现了一种更简洁的写法,一开始用的是Integer.MAX_VALUE,结果被一组数据卡了:[2147483647],只能改成了Long类型。。

代码

//不优雅的写法 4ms
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {

    public boolean checkLeft(TreeNode root, int rootVal) {
        if (root == null) return true;
        if (root.left != null && root.left.val >= rootVal) return false;
        if (root.right != null && root.right.val >= rootVal) return false;
        return checkLeft(root.left, rootVal) && checkLeft(root.right, rootVal);
    }

    public boolean checkRight(TreeNode root, int rootVal) {
        if (root == null) return true;
        if (root.left != null && root.left.val <= rootVal) return false;
        if (root.right != null && root.right.val <= rootVal) return false;
        return checkRight(root.left, rootVal) && checkRight(root.right, rootVal);
    }

    public boolean check(TreeNode root, int rootVal) {
        if (root == null) return true;
        return checkLeft(root.left, rootVal) && checkRight(root.right, rootVal);
    }
    public boolean isValidBST(TreeNode root) {
        if (root == null) return true;
        if (root.left != null && root.left.val >= root.val) return false;
        if (root.right != null && root.right.val <= root.val) return false;
        return isValidBST(root.left) && isValidBST(root.right) && check(root, root.val);
    }
}
//相对优雅的写法,1ms
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {

    public boolean check(TreeNode root, long min, long max) {
        if (root == null) return true;
        return root.val > min 
            && root.val < max
            && check(root.left, min, root.val) 
            && check(root.right, root.val, max);
    }
    public boolean isValidBST(TreeNode root) {
        return check(root, Long.MIN_VALUE, Long.MAX_VALUE);
    }
}

Problem 99. Recover Binary Search Tree

题意

某BST的两个节点位置交换了,尝试找到并恢复之.

思路

这里牵扯到一个定理,那就是中序遍历BST的输出结果必然是递增的,那么被交换的两个位置必定会出现递减情况,找出来然后swap即可.
要说明的是,第一次出现递减情况,比如…a,b,…(a > b),被交换的节点是a,第二次出现递减情况,被交换的节点是b,所以我们还需要维护一个父节点preNode。

代码

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {

    private TreeNode mistake1 = null;

    private TreeNode mistake2 = null;

    private TreeNode preNode = null;

    public void TravInorder(TreeNode root) {
        if (root != null) {
            TravInorder(root.left);
            if (preNode != null && preNode.val >= root.val) {
                if (mistake1 == null) mistake1 = preNode;
                mistake2 = root;
            }
            preNode = root;
            TravInorder(root.right);
        }
    }
    public void recoverTree(TreeNode root) {
        TravInorder(root);
        int tmp = mistake1.val;
        mistake1.val = mistake2.val;
        mistake2.val = tmp;
    }
}

Problem 103. Binary Tree Zigzag Level Order Traversal

题意

从上到下输出一棵二叉树,要求先从左到右,再从右到左,再从左到右。。。.

思路

把102题的代码拿来改改,加个判定就ok。
然而,改了半小时代码,样例永远都是runtime error,再看了下tag,以为是对dfs有限制,又把代码改成了bfs,结果TMD还是runtime error,怒交了一发直接A。。吐槽无力

代码

// recursive
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {
    public List> res = new ArrayList>();

    public void traversal(TreeNode root, int depth) {
        if (root == null) return;
        if (res.size() == depth) res.add(new ArrayList());
        if (depth % 2 == 0) res.get(depth).add(root.val);
        else res.get(depth).add(0, root.val);
        traversal(root.left, depth + 1);
        traversal(root.right, depth + 1);
    }
    public List> zigzagLevelOrder(TreeNode root) {
        if (root == null) return res;
        traversal(root, 0);
        return res;
    }
}
// iterative
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {


    public List> zigzagLevelOrder(TreeNode root) {
        List> res = new ArrayList>();
        if (root == null) return res;
        Queue q = new LinkedList();
        Queue level = new LinkedList();
        q.add(root); 
        level.add(0);
        while (q.size() != 0) {
            TreeNode node = q.poll();
            int depth = level.poll();

            if (res.size() == depth) res.add(new ArrayList());
            if (depth % 2 == 0) res.get(depth).add(node.val);
            else res.get(depth).add(0, node.val);
            if (node.left != null) {
                q.add(node.left);
                level.add(depth + 1);
            }
            if (node.right != null) {
                q.add(node.right);
                level.add(depth + 1);
            }
        }
        return res;
    }
}

Problem 105. Construct Binary Tree from Preorder and Inorder Traversal

题意

输入一棵二叉树的先序遍历与中序遍历的结果,输出该二叉树.

思路

先序定root,中序分左右,遍历先序序列,再找到中序序列中同样value的节点,划分左右子树,分治执行下去,直到划分完毕.

代码

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {

    public TreeNode buildTree(int[] pre, int[] in, int idx, int start, int end) {
        if (idx >= pre.length || start > end) {
            return null;
        }
        TreeNode root = new TreeNode(pre[idx]);
        int x = end;
        for (; x > start; x--)
            if (pre[idx] == in[x]) break;

        root.left = buildTree(pre, in, idx + 1, start, x - 1);
        root.right = buildTree(pre, in, idx + x - start + 1, x + 1, end);
        return root;
    }

    public TreeNode buildTree(int[] preorder, int[] inorder) {
        return buildTree(preorder, inorder, 0, 0, preorder.length - 1);
    }


}

Problem 106. Construct Binary Tree from Inorder and Postorder Traversal

题意

输入一棵二叉树的后序遍历与中序遍历的结果,输出该二叉树.

思路

和problem的做法完全是对称的,后序遍历定root,中序遍历分左右.

代码

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {

    public TreeNode buildTree(int[] in, int[] post, int idx, int start, int end) {
        if (idx < 0 || start > end)
            return null;

        TreeNode root = new TreeNode(post[idx]);
        int x = start;
        for (; x < end; x++) {
            if (post[idx] == in[x]) break;
        }

        root.left = buildTree(in, post, idx - end + x - 1, start, x - 1);
        root.right = buildTree(in, post, idx - 1, x + 1, end);
        return root;
    }

    public TreeNode buildTree(int[] inorder, int[] postorder) {
        return buildTree(inorder, postorder, postorder.length - 1, 0, postorder.length - 1);
    }
}

Problem 108. Convert Sorted Array to Binary Search Tree

题意

输入一个升序排序后的数组,为其建一棵平衡BST.

思路

二分即可.

代码

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {

    public TreeNode sortedArrayToBST(int[] nums, int start, int end) {
        if (start > end) return null;
        int mid = (start + end) >> 1;
        TreeNode root = new TreeNode(nums[mid]);
        root.left = sortedArrayToBST(nums, start, mid - 1);
        root.right = sortedArrayToBST(nums, mid + 1, end);
        return root;
    }

    public TreeNode sortedArrayToBST(int[] nums) {
        return sortedArrayToBST(nums, 0, nums.length - 1);
    }
}

Problem 113. Path Sum II

题意

Problem 112 的进阶版本,输入一棵二叉树与一个整数sum,输出所有从根节点到叶节点经过节点值之和为sum的路径.

思路

不同于112,这题麻烦在可能有多种解,适合用回溯法来求解,而使用回溯法需要注意的一点就是不同分支之间不能相互影响。
例如有二叉树如下:[1,2,3,6,7,4,5],sum = 9
如果在递归过程中没有消除分支影响,就很有可能出现[1,2,3,4],[1,3,4,5]等不可能路径,所以在递归一个分支的情况时,处理过程结束后一定要撤销该分支对其他分支的影响【例如这题就需要在处理完一个节点(表示该分支选择了此节点)后,从list中删去该节点(表示其他分支没选择此节点)】

代码

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {

    public List<List<Integer>> res = new ArrayList<List<Integer>>();

    public void traversal(TreeNode root, List<Integer> list, int sum) {
        if (root == null) return;
        list.add(root.val);
        if (root.left == null && root.right == null) {
            if (root.val == sum)
                res.add(new ArrayList<Integer>(list));
            list.remove(list.size() - 1);    
            return;
        }
        if (root.left != null) traversal(root.left, list, sum - root.val);
        if (root.right != null) traversal(root.right, list, sum - root.val);
        list.remove(list.size() - 1);
    }
    public List<List<Integer>> pathSum(TreeNode root, int sum) {
        traversal(root, new ArrayList<Integer>(), sum);
        return res;
    }
}

Problem 114. Flatten Binary Tree to Linked List

题意

将一棵二叉树改造成扁平的,也就是依先序遍历顺序的链表形式的二叉树,right即next节点,left节点为null.

思路

写了一份用虽然A了但是极其不优雅的代码。。
方法是先用辅助list保存先序遍历的结果,再按要求建树,空间极大浪费【可耻!】
后来在Discuss区发现了一份Amazing的代码。。让我觉得二叉树必须优雅!不优雅的二叉树代码和咸鱼有什么区别!
优雅代码的做法是反其道而行之,先右再左最后根,把遍历到的根节点left指向null,right指向prev节点,prev节点一开始指null,然后维护prev = root。

代码

// 不!优!雅!
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {

    private List list = new ArrayList();
    private void preTraversal(TreeNode root) {
        if (root == null) return;
        list.add(root);
        preTraversal(root.left);
        preTraversal(root.right);
    }
    private void buildTree(TreeNode root, int pos) {
        if (pos == list.size() - 1) return;
        root.right = list.get(pos + 1);
        root.left = null;
        buildTree(root.right, pos + 1);
    }
    public void flatten(TreeNode root) {
        if (root == null) return;
        preTraversal(root);
        buildTree(root, 0);
    }
}
// 很!优!雅!
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {

    private TreeNode prev = null;
    public void flatten(TreeNode root) {
        if (root == null) return;
        flatten(root.right);
        flatten(root.left);
        root.right = prev;
        root.left = null;
        prev = root;
    }
}

Problem 116. Populating Next Right Pointers in Each Node

题意

Populate each next pointer to point to its next right node. If there is no next right node, the next pointer should be set to NULL.

Initially, all next pointers are set to NULL..

思路

见代码.

代码

/**
 * Definition for binary tree with next pointer.
 * public class TreeLinkNode {
 *     int val;
 *     TreeLinkNode left, right, next;
 *     TreeLinkNode(int x) { val = x; }
 * }
 */
public class Solution {
    public void connect(TreeLinkNode root) {
        if (root == null) return;
        if (root.left != null) root.left.next = root.right;
        if (root.right != null && root.next != null) root.right.next = root.next.left;
        connect(root.left);
        connect(root.right);
    }
}

Problem 129. Sum Root to Leaf Numbers

题意

输入一棵节点值均为0-9的二叉树,定义每一条根节点到叶节点的路径的值为节点值组成的整数,如1->2->3值为123,求所有路径值之和.

思路

比较简单的dfs,开始的时候怕Integer溢出,借用了一下String来存储路径值,后来发现想多了。。所以写了一份用String一份没用String的.

代码

// 使用String
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {

    public int res = 0;
    public void dfs(TreeNode root, String path) {
        if (root == null) return;
        path += Integer.toString(root.val);
        if (root.left == null && root.right == null) {
            res += Integer.parseInt(path);
            return;
        }
        dfs(root.left, path);
        dfs(root.right, path);
    }
    public int sumNumbers(TreeNode root) {
        dfs(root, "");
        return res;
    }
}
// 不用String
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {

    public int dfs(TreeNode root, int path) {
        if (root == null) return 0;
        int sum = (path << 1) + (path << 3) + root.val;
        if (root.left == null && root.right == null) return sum;
        else return dfs(root.left, sum) + dfs(root.right, sum);
    }
    public int sumNumbers(TreeNode root) {
        return dfs(root, 0);
    }
}

Problem 144. Binary Tree Preorder Traversal

题意

迭代先序遍历二叉树.

思路

先把root节点添加进list里,再用栈把右节点保存起来,把左节点保存起来,取top元素为root。

代码

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {
    public List preorderTraversal(TreeNode root) {
        List res = new ArrayList();
        if (root == null) return res;
        Stack s = new Stack();
        s.push(root);
        while (!s.empty()) {
            root = s.pop();
            if (root != null) {
                res.add(root.val);
                s.push(root.right);
                s.push(root.left);
            }
        }
        return res;
    }
}

Problem 173. Binary Search Tree Iterator

题意

实现一个BST迭代器,有hasNext与next两个接口,next依次返回最小的元素.

思路

用Queue+Stack实现了一个比较简单的,构造函数是O(n)的时间复杂度,两个接口时间复杂度都接近O(1),交上去也A了,后来发现题目希望给一个空间复杂度能在O(h)【h即BST高度】左右的,于是发现了一种只用Stack的解法。

代码

// Stack + Queue
/**
 * Definition for binary tree
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */

public class BSTIterator {

    private Queue q = new LinkedList();
    public BSTIterator(TreeNode root) {
        Stack s = new Stack();
        while (!s.empty() || root != null) {
            if (root != null) {
                s.push(root);
                root = root.left;
            } else {
                root = s.pop();
                q.add(root.val);
                root = root.right;
            }
        }
    }

    /** @return whether we have a next smallest number */
    public boolean hasNext() {
        return !q.isEmpty();
    }

    /** @return the next smallest number */
    public int next() {
        return q.poll();
    }
}

/**
 * Your BSTIterator will be called like this:
 * BSTIterator i = new BSTIterator(root);
 * while (i.hasNext()) v[f()] = i.next();
 */
// Only a stack
/**
 * Definition for binary tree
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */

public class BSTIterator {

    private Stack s = new Stack();
    public BSTIterator(TreeNode root) {
        while (root != null) {
            s.push(root);
            root = root.left;
        }
    }

    /** @return whether we have a next smallest number */
    public boolean hasNext() {
        return !s.isEmpty();
    }

    /** @return the next smallest number */
    public int next() {
        TreeNode root = s.pop();
        TreeNode tmp = root.right;
        while (tmp != null) {
            s.push(tmp);
            tmp = tmp.left;
        }
        return root.val;
    }
}

/**
 * Your BSTIterator will be called like this:
 * BSTIterator i = new BSTIterator(root);
 * while (i.hasNext()) v[f()] = i.next();
 */

Problem 199. Binary Tree Right Side View

题意

输入一棵二叉树,返回该二叉树的右视节点图.

思路

有一个比较巧妙的地方,右视图的特性在于两点:一是每层只有一个节点,二是一切以右节点为先。于是可以通过右视图大小与节点深度的比较来判断是否需要将此节点加入右视图.

代码

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {

    private List res = new ArrayList();

    private void dfs(TreeNode root, int depth) {
        if (root == null) return;
        if (res.size() == depth) res.add(root.val);
        dfs(root.right, depth + 1);
        dfs(root.left, depth + 1);
    }
    public List rightSideView(TreeNode root) {
        dfs(root, 0);
        return res;
    }
}

Problem 222. Count Complete Tree Nodes

题意

计算一棵完全二叉树的节点个数.
ps. 完全二叉树定义:wiki 百度百科

思路

将完全二叉树分成几棵满二叉树来做,见代码。

代码

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {
    private int dfs(TreeNode root) {
        int left = count(root, true);
        int right = count(root, false);
        if (left == right) return (1 << left) - 1;
        return 1 + dfs(root.left) + dfs(root.right);
    }
    private int count(TreeNode root, boolean isLeft) {
        int count = 0;
        if (isLeft) {
            while (root != null) {
                count ++;
                root = root.left;
            }
        } else {
            while (root != null) {
                count ++;
                root = root.right;
            }
        }
        return count ;
    }
    public int countNodes(TreeNode root) {
        return dfs(root);
    }

}

Problem 230. Kth Smallest Element in a BST

题意

求一棵BST上的第k大元素.

思路

第一时间想到的解法是排序后输出第k项。。活该永远是弱鸡
BST有个性质很关键,那就是中序遍历BST的路径永远是升序的,这样我们就可以在最差O(n)的时间里求出k-th元素.
关于这一题,hint上写了,能否有一种通过修改BST数据结构来实现的高效解法,后来在discuss发现了这种方式,建树O(n),查询O(log n)
详情可以看这里

代码

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {

    private int ans, count;
    private void dfs(TreeNode root) {
        if (root == null) return;
        dfs(root.left);
        count--;
        if (count == 0) {
            ans = root.val;
            return;
        }
        dfs(root.right);
    }

    public int kthSmallest(TreeNode root, int k) {
        count = k;
        dfs(root);
        return ans;
    }
}

Problem 236. Lowest Common Ancestor of a Binary Tree

题意

求一棵二叉树上两个节点的LCA.

思路

见代码.

代码

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if (root == null || root == p || root == q) return root;
        TreeNode left = lowestCommonAncestor(root.left, p, q);
        TreeNode right = lowestCommonAncestor(root.right, p, q);
        if (left != null && right != null) return root;
        return left == null? right: left;
    }
}

Problem 337. House Robber III

题意

有一个小偷准备在二叉树形分布的各个房间中盗窃财物,每个房间可以看作一个二叉树的节点,房间财物价值为节点值,若两个链接并且相邻的房间均被盗窃,就会被警察发现,输入二叉树,求小偷可获得财物最大价值.

思路

一开始觉得这是傻逼题,最优方案就只有两种,全选奇数level的节点或偶数level的节点,比较下这两种方案不就行了,结果被教做人了。。
考虑[2,3,null,1,null,4]这种情况,最优明显是2+4,但按照之前的算法答案是5,所以最优解不一定只有两种。
考虑当前节点root,有两种选择分支,即
1. root+root.left.left+root.left.right+root.right.left+root.right.right
2. root.left+root.right
然后比较两分支价值,递归地比较下去即可。

后来参考了一下discuss面板,发现这简直是一道好题,除了上述解法,还可以利用哈希表或中间数组来维护局部最优解,以达到对该算法进行进一步优化:
详细题解戳这里

代码

// Level 1: 基本算法 
// Run time: 1202ms
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {

    public int rob(TreeNode root) {
        if (root == null) return 0;
        int val = 0;
        if (root.left != null)
            val += rob(root.left.left) + rob(root.left.right);
        if (root.right != null)
            val += rob(root.right.left) + rob(root.right.right);
        val = Math.max(val + root.val, rob(root.left) + rob(root.right));
        return val;
    }
}
// Level 2: 利用Hash-Table优化
// Run time: 9ms
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {

    private Map map = new HashMap();
    private int dfs(TreeNode root) {
        if (root == null) return 0;
        if (map.containsKey(root)) return map.get(root);
        int val = 0;
        if (root.left != null) val += dfs(root.left.left) + dfs(root.left.right);
        if (root.right != null) val += dfs(root.right.left) + dfs(root.right.right);
        val = Math.max(val + root.val, dfs(root.left) + dfs(root.right));
        map.put(root, val);
        return val;
    }
    public int rob(TreeNode root) {
        return dfs(root);
    }
}
// Level 3: 利用中间数组优化
// Run time: 1ms
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {

    private int[] dfs(TreeNode root) {
        if (root == null) return new int[2];
        int[] left = dfs(root.left);
        int[] right = dfs(root.right);
        int[] res = new int[2];
        res[0] = Math.max(left[0], left[1]) + Math.max(right[0], right[1]);
        res[1] = root.val + left[0] + right[0];
        return res;
    }
    public int rob(TreeNode root) {
        int[] res = dfs(root);
        return Math.max(res[0], res[1]);
    }
}

Hard过几天再做吧。。

你可能感兴趣的:(数据结构)