LintCode二叉树&递归分治题总结

来源:互联网 发布:淘宝妹子爱吃的零食 编辑:程序博客网 时间:2024/06/05 11:29

先来几个推荐的参考博客链接:

漫谈递归——递归的思想

非递归遍历二叉树总结

二叉树题总结

LintCode中二叉树与分治法那章有这么些题目:



376. Binary Tree Path Sum

要求等于target从根节点到叶子节点的路径和的组合,用DFS。

递归需要注意的是,终止情况是什么,也就是遇到叶子节点的时候返回,如果遇到叶子节点的时候恰好满足路径和等于target,就把这条路径加到总结果里面。

然后就是递归的主题,遇到左子节点、遇到右子节点的时候进入子递归。然后记得加入path路径后要remove掉,以方便保持当前路径的唯一性。

    public List<List<Integer>> binaryTreePathSum(TreeNode root, int target) {        List<List<Integer>> res = new ArrayList();        if (root == null) {            return res;        }        ArrayList<Integer> path = new ArrayList<Integer>();        path.add(root.val);        dfs(res, path, root, target, root.val);        return res;    }    private void dfs(List<List<Integer>> res, ArrayList<Integer> path, TreeNode root, int target, int sum) {        // 遇到叶子节点的返回条件        if (root.left == null && root.right == null) {            if (sum == target) {                res.add(new ArrayList<Integer>(path));            }            return;        }                if (root.left != null) {            path.add(root.left.val);            dfs(res, path, root.left, target, sum + root.left.val);            path.remove(path.size() - 1);        }                if (root.right != null) {            path.add(root.right.val);            dfs(res, path, root.right, target, sum + root.right.val);            path.remove(path.size() - 1);        }    }

469. Identical Binary Tree

判断两个二叉树是否是完全一样的,连结构也要一样。很明显考的是递归。既然是递归,就注意终结条件,

自然是对不同情况的判断,参数就2个,2个树的root。

1)2个root皆空,则是identical的

2)2个root只有一个空,则非identical

3)2个root皆不空,并且root值不等,则非identical

4)2个root皆不空,并且root值相等,则进行子递归判断左子树和右子树

    public boolean isIdentical(TreeNode a, TreeNode b) {        if (a == null && b == null) {            return true;        }        if (a == null || b == null) {            return false;        }        if (a.val != b.val) {            return false;        }        return isIdentical(a.left, b.left) && isIdentical(a.right, b.right);    }

470. Tweaked Identical Binary Tree

也是判断2个二叉树是否完全一样,但是与上道题不同之处在于允许了对称扭曲。同样也是分4种情况判断:

    public boolean isTweakedIdentical(TreeNode a, TreeNode b) {        if (a == null && b == null) {            return true;        }        if (a == null || b == null) {            return false;        }        if (a.val == b.val) {            return (isTweakedIdentical(a.left, b.right) && isTweakedIdentical(b.left, a.right)) || (isTweakedIdentical(a.left, b.left) && isTweakedIdentical(b.right, a.right));        }        return false;    }

468. Symmetric Binary Tree

判断一颗二叉树是不是对称的,跟上道题很像,只要把这颗树的左右子节点作为参数传进去就好。

    public boolean isSymmetric(TreeNode root) {        if (root == null) {            return true;        }        if (root.left == null && root.right == null) {            return true;        }        return helper(root.left, root.right);    }    public boolean helper(TreeNode a, TreeNode b) {        if (a == null && b == null) {            return true;        }        if (a == null || b == null) {            return false;        }        if (a.val == b.val) {            return (helper(a.left, b.right) && helper(b.left, a.right));        }        return false;    }

467. Complete Binary Tree

判断一棵树是不是完全二叉树。一个思路就是层次遍历,把每层的节点从左向右依此加入Stack,然后把Stack上层的None弹出,最后检查如果Stack中还有None说明不是Complete Tree 比如上面的不完全二叉树生成的数组为[1, 2, 3, None, 4, None, None],将右侧None弹出后为[1, 2, 3, None, 4],循环查找,发现还有None存在,所以是不完全二叉

    public boolean isComplete(TreeNode root) {        if (root == null) {            return true;        }        Queue<TreeNode> q = new LinkedList<TreeNode>();        q.offer(root);        boolean isNull = false;        while (!q.isEmpty()) {            TreeNode node = q.poll();            if (node.left != null) {                if (isNull == true) {                    return false;                }                q.offer(node.left);            } else {                isNull = true;            }                        if (node.right != null) {                if (isNull == true) {                    return false;                }                q.offer(node.right);            } else {                isNull = true;            }        }        return true;    }

还有另外一种方法是递归,比较难理解,可以参考这篇博文:http://www.geeksforgeeks.org/check-whether-binary-tree-complete-not-set-2-recursive-solution/

或者参考这篇博客:http://stackoverflow.com/questions/1442674/how-to-determine-whether-a-binary-tree-is-complete


97. Maximum Depth of Binary Tree

求一个二叉树的最大深度。

    public int maxDepth(TreeNode root) {        if (root == null) {            return 0;        }        return 1 + Math.max(maxDepth(root.left), maxDepth(root.right));    }

155. Minimum Depth of Binary Tree

求二叉树的最小深度,最小深度,就是从根节点到叶子节点最近的一条路的长度。不递归的话,可以用BFS层级遍历来做。

    public int minDepth(TreeNode root) {        if (root == null) {            return 0;        }        Queue<TreeNode> q = new LinkedList<TreeNode>();        q.offer(root);        int depth = 0;        while (!q.isEmpty()) {            int length = q.size();            depth++;            for (int i = 0; i < length; i++) {                TreeNode n = q.poll();                if (n.left == null && n.right == null) {                    return depth;                }                if (n.left != null) {                    q.offer(n.left);                }                if (n.right != null) {                    q.offer(n.right);                }            }                    }        return depth;    }
也可以用递归来做,当当前节点是叶子节点时就返回结果。

    public int minDepth(TreeNode root) {        if (root == null) {            return 0;        }        if (root.left == null && root.right == null) {            return 1;        }        int l = (root.left == null) ? Integer.MAX_VALUE : minDepth(root.left);         int r = (root.right == null) ? Integer.MAX_VALUE : minDepth(root.right);        return 1 + Math.min(l, r);    }

93. Balanced Binary Tree

判断一棵树是否为平衡二叉树。如果左右子树的最大高度差超过1的话,那就不是平衡的了。所以这道题是基于求树的最大高度的。

一开始可能会以为直接对左子树和右子树求高度,然后比较两树的高度差。这样的想法是错误的,比如下面这个树就不是平衡的。


所以在递归的过程中,对每一个节点进行高度平衡判断。只要中途有不平衡,那就是不平衡。如果左子树不平衡,那就是不平衡;如果右子树不平衡,那也是不平衡。

    private int depth(TreeNode root) {        if (root == null) {            return 0;        }        int l = depth(root.left);        int r = depth(root.right);        if (Math.abs(l-r) > 1 || l == -1 || r == -1) {            return -1;        }        return 1 + Math.max(l, r);    }    public boolean isBalanced(TreeNode root) {        return depth(root) != -1;    }


88. Lowest Common Ancestor

求最近公共父节点。参数是1个root节点和2个输入节点A、B。求得就是A和B的最近公共父节点。

查找两个node的最早的公共祖先,分三种情况: 

1. 如果两个node在root的两边,那么最早的公共祖先就是root。 

2. 如果两个node在root的左边,那么把root.left作为root,再递归。 

3. 如果两个node在root的右边,那么把root.right作为root,再递归。

    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode A, TreeNode B) {        if (root == null || root == A || root == B) {            return root;        }        // divide        TreeNode l = lowestCommonAncestor(root.left, A, B);        TreeNode r = lowestCommonAncestor(root.right, A, B);                // conquer        if (l != null && r != null) {            return root;        }        if (l != null) {            return l;        }        if (r != null) {            return r;        }        return null;    }

474. Lowest Common Ancestor II

跟上道题类似,不过节点之间的关系是parent node的关系了。

如果每个结点都有一个指针指向它的父结点,于是我们可以从任何一个结点出发,得到一个到达树根结点的单向链表。因此这个问题转换为两个单向链表的第一个公共结点。

    public ParentTreeNode lowestCommonAncestorII(ParentTreeNode root,                                                 ParentTreeNode A,                                                 ParentTreeNode B) {        Stack<ParentTreeNode> s1 = new Stack();        Stack<ParentTreeNode> s2 = new Stack();        s1.push(A);        s2.push(B);        while (s1.peek().parent != null) {            s1.push(s1.peek().parent);        }        while (s2.peek().parent != null) {            s2.push(s2.peek().parent);        }        if (s1.empty() || s2.empty()) {            return root;        }        ParentTreeNode res = null;        while (!s1.empty() && !s2.empty() && s1.peek() == s2.peek()) {            res = s1.pop();            s2.pop();        }        return res;    }

85. Insert Node in a Binary Search Tree

如果是用非递归的方法,则用一个while循环,找到那个需要插入的地方的父节点。

    public TreeNode insertNode(TreeNode root, TreeNode node) {        if (root == null) {            return node;        }                TreeNode res = root;        TreeNode father = null;        while (root != null) {            father = root;            if (node.val > root.val) {                root = root.right;            } else {                root = root.left;            }        }        if (node.val > father.val) {            father.right = node;        } else {            father.left = node;        }        return res;    }
如果是用递归的话,那看起来就比较简单了:
    public TreeNode insertNode(TreeNode root, TreeNode node) {        if (root == null) {            return node;        }        if (node.val > root.val) {            root.right = insertNode(root.right, node);        } else {            root.left = insertNode(root.left, node);        }        return root;    }


87. Remove Node in Binary Search Tree

难度为Hard,Acceptance为25%.

首先,该题在《算法导论》一书中是有的。思路也较为容易理解,关键是实现算法时需要注意的各种细节。

那么下面说明该题的思路:

第一步,当然是找到要删除的节点node和它的父节点parent,这里采用普通的二分查找方法,找到了就返回node的父节点parent,找不到就返回null

第二步,就是删除该node节点,按照算法导论上的那个算法,删除node节点分为3种情况,1)node没有左右儿子,那么就直接把node的父节点指向node的儿子,即指向null。2)node只有一个儿子(左儿子或者右儿子),这个时候就直接把node的父节点指向左右儿子。3)node有2个儿子,那么这个时候就从左子树里面找到最小的那个节点,来代替node节点。

为了代码简洁,上述的3种情况可以简化为2种情况:

node没有左右儿子、node只有左儿子,可以合并为一种情况:即node的右子树不存在。此时,直接用parent节点的子节点指向该node节点的左节点。

node只有右儿子、node有左右2各儿子,可以合并为一种情况:即node的右子树存在。此时,需要找到node的右子树里的最小节点,用该节点替换node节点。

技巧:因为要删除的节点可能是根节点,因此为了算法的通用性,可以首先new一个dummy节点,该节点的左节点指向根节点,这样处理起来更为方便。

    public TreeNode removeNode(TreeNode root, int key) {        TreeNode dummy = new TreeNode(0);        dummy.left = root;        TreeNode parent = find(dummy, root, key);        TreeNode node = null;        // node 不存在        if (parent == null) {            return root;        }        // node 在左边        if (parent.left != null && parent.left.val == key) {            node = parent.left;        }        // node 在右边        if (parent.right != null && parent.right.val == key) {            node = parent.right;        }                deleteNode(parent, node);        return dummy.left;    }    private TreeNode find(TreeNode parent, TreeNode node, int key) {        if(node == null) {            return null;        }        if (key == node.val) {            return parent;        }        if (key > node.val) {            return find(node, node.right, key);        } else {            return find(node, node.left, key);        }    }    private void deleteNode(TreeNode parent, TreeNode node) {        // node的右子树不存在, 处理了两种情况,即只有左子树或者没有子树        if (node.right == null) {            if (parent.right == node) {                parent.right = node.left;            } else {                parent.left = node.left;            }        } else {            // node的右子树存在, 且左子树不存在            if (node.left == null) {                if (parent.right == node) {                    parent.right = node.right;                } else {                    parent.left = node.right;                }            } else {                // node的左右子树都存在,则寻找node右子树的最小节点,用于取代node                TreeNode father = node;                TreeNode t = node.right;                                while (t.left != null) {                    father = t;                    t = t.left;                }                if (father.left == t) {                    father.left = t.right;                } else {                    father.right = t.right;                }                node.val = t.val;            }        }    }


11. Search Range in Binary Search Tree

给定一个区间,要求在一个二叉查找树中,找到所有处在这个区间中的节点。最简单的思路就是先用dfs遍历,遍历过程中发现符合条件就加入ArrayList中。最后再对数组排序,返回。但是其实细细一想,是否可以免去这个排序的过程呢?是否可以在遍历的时候就能保持有序呢?考虑到二叉查找树的性质,如果用中序遍历,是可以保证这个的。

    public void dfs(TreeNode root, ArrayList<Integer> res, int k1, int k2) {        if (root != null) {            dfs(root.left, res, k1, k2);            if (root.val >= k1 && root.val <= k2) {                res.add(root.val);            }            dfs(root.right, res, k1, k2);        }    }    public ArrayList<Integer> searchRange(TreeNode root, int k1, int k2) {        ArrayList<Integer> res = new ArrayList();        dfs(root, res, k1, k2);        return res;    }


66. Binary Tree Preorder Traversal

67. Binary Tree Inorder Traversal

68. Binary Tree Postorder Traversal

二叉树的前中后序遍历,递归的非常简单,就不再赘述了,非递归的可以参考这篇博客:http://zisong.me/post/suan-fa/geng-jian-dan-de-bian-li-er-cha-shu-de-fang-fa



69. Binary Tree Level Order Traversal

二叉树层次遍历,这个算法已经烂大街了,就不多说了

    public ArrayList<ArrayList<Integer>> levelOrder(TreeNode root) {        ArrayList<ArrayList<Integer>> res = new ArrayList();        if (root == null) {            return res;        }        Queue<TreeNode> queue = new LinkedList<TreeNode>();        queue.offer(root);                while(!queue.isEmpty()) {            ArrayList<Integer> level = new ArrayList();            int size = queue.size();            for (int i = 0; i < size; i++) {                TreeNode tmp = queue.poll();                level.add(tmp.val);                if (tmp.left != null) {                    queue.offer(tmp.left);                }                if (tmp.right != null) {                    queue.offer(tmp.right);                }            }            res.add(level);        }        return res;    }

70. Binary Tree Level Order Traversal II

也是二叉树的层次遍历,不过是从叶子节点到根节点了,跟上道题类似,把最后的数组reverse一下就得到了。

就在上面的代码的最后加上这么一句就行:

Collections.reverse(res);

71. Binary Tree Zigzag Level Order Traversal

“之”字型的层次遍历,加个变量判断一下奇偶数就好。

    public ArrayList<ArrayList<Integer>> zigzagLevelOrder(TreeNode root) {        ArrayList<ArrayList<Integer>> res = new ArrayList();        if (root == null) {            return res;        }        Queue<TreeNode> queue = new LinkedList<TreeNode>();        queue.offer(root);                int level = 1;        while(!queue.isEmpty()) {            ArrayList<Integer> path = new ArrayList();            int size = queue.size();            level++;            for (int i = 0; i < size; i++) {                TreeNode tmp = queue.poll();                path.add(tmp.val);                if (tmp.left != null) {                    queue.offer(tmp.left);                }                if (tmp.right != null) {                    queue.offer(tmp.right);                }            }            if (level % 2 == 1) {                Collections.reverse(path);            }            res.add(path);        }        return res;    }

72. Construct Binary Tree from Inorder and Postorder Traversal

根据中序遍历和后续遍历结果,构建出那颗二叉树。要知道如何构建二叉树,首先我们需要知道二叉树的几种遍历方式,譬如有如下的二叉树:

                1        --------|-------        2               3    ----|----       ----|----    4       5       6       7

前序遍历 1245367 

中序遍历 4251637 

后续遍历 4526731

仍然以上面那棵二叉树为例,我们可以发现,对于后序遍历来说,最后一个元素一定是根节点,也就是1。然后我们在中序遍历的结果里面找到1所在的位置,那么它的左半部分就是其左子树,有半部分就是其右子树。

我们将中序遍历左半部分425取出,同时发现后序遍历的结果也在相应的位置上面,只是顺序稍微不一样,也就是452。我们可以发现,后序遍历中的2就是该子树的根节点。

上面说到了左子树,对于右子树,我们取出637,同时发现后序遍历中对应的数据偏移了一格,并且顺序也不一样,为673。而3就是这颗右子树的根节点。

重复上述过程,通过后续遍历找到根节点,然后在中序遍历数据中根据根节点拆分成两个部分,同时将对应的后序遍历的数据也拆分成两个部分,重复递归,就可以得到整个二叉树了。

    private TreeNode build(int[] in, int instart, int inend, int[] post, int poststart, int postend) {        if (instart > inend) {            return null;        }        TreeNode root = new TreeNode(post[postend]);        int pos = -1;        for (int i = 0; i <= inend; i++) {            if (in[i] == post[postend]) {                pos = i;            }        }        root.left = build(in, instart, pos - 1, post, poststart, poststart + pos - instart - 1);        root.right = build(in, pos + 1, inend, post, poststart + pos - instart, postend - 1);                return root;    }    public TreeNode buildTree(int[] in, int[] post) {        return build(in, 0, in.length - 1, post, 0, post.length - 1);    }

73. Construct Binary Tree from Preorder and Inorder Traversal

根据后续和中序遍历结果,构建出那颗二叉树。参考:https://siddontang.gitbooks.io/leetcode-solution/content/tree/construct_binary_tree.html

    private TreeNode build(int[] pre, int prestart, int preend, int[] in, int instart, int inend) {        if (instart > inend) {            return null;        }        TreeNode root = new TreeNode(pre[prestart]);        int pos = -1;        for (int i = 0; i <= inend; i++) {            if (in[i] == pre[prestart]) {                pos = i;            }        }        root.left = build(pre, prestart + 1, prestart + pos - instart, in, instart, pos - 1);        root.right = build(pre, prestart + pos - instart + 1, preend, in, pos + 1, inend);                return root;    }    public TreeNode buildTree(int[] pre, int[] in) {        return build(pre, 0, pre.length - 1, in, 0, in.length - 1);    }

7. Binary Tree Serialization

可以把二叉树序列化String,也可以把String版本的二叉树还原成节点版本的二叉树。可参见这篇博客:http://blog.csdn.net/ljiabin/article/details/49474445


    public String serialize(TreeNode root) {        String res = "";        if (root == null) {            return res;        }        Queue<TreeNode> q = new LinkedList<TreeNode>();        q.offer(root);        res += root.val;        res += ',';        while (!q.isEmpty()) {            int length = q.size();            for (int i = 0; i < length; i++) {                TreeNode node = q.poll();                if (node.left != null) {                    q.offer(node.left);                    res += node.left.val;                    res += ',';                } else {                    res += "#,";                }                if (node.right != null) {                    q.offer(node.right);                    res += node.right.val;                    res += ',';                } else {                    res += "#,";                }            }        }        return res;    }        public TreeNode deserialize(String data) {        if (data == null || data == "") {            return null;        }        String[] res = data.split(",");        // 节点i之前null节点的个数        int[] nums = new int[res.length];        TreeNode[] arr = new TreeNode[res.length];        for (int i = 0; i < res.length; i++) {            if (i > 0) {                nums[i] = nums[i - 1];            }            if (res[i].equals("#")) {                arr[i] = null;                nums[i]++;            } else {                arr[i] = new TreeNode(Integer.parseInt(res[i]));            }        }        for (int i = 0; i < res.length; i++) {            if (arr[i] != null) {                arr[i].left = arr[(i - nums[i]) * 2 + 1];                arr[i].right = arr[(i - nums[i]) * 2 + 2];            }        }        return arr[0];    }

475. Binary Tree Maximum Path Sum II

找到一个二叉树从root到叶子节点的最大的一个路径和,非常简单的递归,但是需要考虑的问题是,节点可能是负数。所以每次返回的时候,是选择(左节点,右节点,0)的最大值:

    public int maxPathSum2(TreeNode root) {        if (root == null) {            return 0;        }        return root.val + Math.max(0, Math.max(maxPathSum2(root.left), maxPathSum2(root.right)));    }


94. Binary Tree Maximum Path Sum

求一个二叉树的最大路径和,可以从任意节点到任意节点。

最优路径上的节点一定是连续的,不能中断

最优路径中一定包含某个子树的根节点

写一个递归函数,实现计算根节点到任意点的最大路径和,以及穿过根节点的最大路径和,用一个全局变量保存最优解。

需要注意的是,节点可能会包含负数,所以计算的时候,要判断一下负数。

    private int res = Integer.MIN_VALUE;    private int helper(TreeNode root) {        if (root == null) {            return Integer.MIN_VALUE;        }        // divide        int left = helper(root.left);        int right = helper(root.right);        // conquer        int root2any = Math.max(Math.max(left, right), 0) + root.val;        int any2any = Math.max(0, left) + Math.max(0, right) + root.val;        res = Math.max(res, Math.max(root2any, any2any));        return root2any;    }    public int maxPathSum(TreeNode root) {        if (root == null) {            return Integer.MIN_VALUE;        }        helper(root);        return res;    }

448. Inorder Successor in Binary Search Tree

找到一个节点的中序后继节点。我的思路是先通过中序遍历得到一个有序的数组,然后再在这个数组中二分查找,找到那个节点。这个算法比九章的标准答案还要快些

    private void inorder(TreeNode root, ArrayList<TreeNode> res) {        if (root != null) {            inorder(root.left, res);            res.add(root);            inorder(root.right, res);        }    }    private int binarySearch(ArrayList<TreeNode> res, int val) {        int start = 0, end = res.size() - 1;        while (start + 1 < end) {            int mid = start + (end - start) / 2;            if (res.get(mid).val == val) {                if (mid + 1 < res.size()) {                    return mid + 1;                } else {                    return -1;                }            } else if (val > res.get(mid).val) {                start = mid;            } else {                end = mid;            }        }        if (res.get(start).val == val && start + 1 < res.size()) {            return start + 1;        }        if (res.get(end).val == val && end + 1 < res.size()) {            return end + 1;        }        return -1;    }    public TreeNode inorderSuccessor(TreeNode root, TreeNode p) {        ArrayList<TreeNode> res = new ArrayList();        if (root == null || p == null) {            return null;        }        inorder(root, res);        int pos = binarySearch(res, p.val);        if (pos != -1) {            return res.get(pos);        }        return null;    }


95. Validate Binary Search Tree

判断一颗二叉树是不是合法的二分查找树,这时可以用到一个性质,如果它的中序遍历的结果是非递减的,拿它就是合法的:

    private void inorder(TreeNode root, ArrayList<Integer> list) {        if (root != null) {            inorder(root.left, list);            list.add(root.val);            inorder(root.right, list);        }    }    public boolean isValidBST(TreeNode root) {        ArrayList<Integer> list = new ArrayList();        inorder(root, list);        for (int i = 1; i < list.size(); i++) {            if (list.get(i) <= list.get(i - 1)) {                return false;            }        }        return true;    }


86. Binary Search Tree Iterator

算是一道系统设计题,给定一些函数接口,要你按照要求实现。实现一个iterator可以遍历二叉树。我用的是中序遍历,把整个树保存在一个ArrayList中,然后用一个pos变量记录当前位置。比九章的标准答案还要快一点:

/** * Definition of TreeNode: * public class TreeNode { *     public int val; *     public TreeNode left, right; *     public TreeNode(int val) { *         this.val = val; *         this.left = this.right = null; *     } * } * Example of iterate a tree: * BSTIterator iterator = new BSTIterator(root); * while (iterator.hasNext()) { *    TreeNode node = iterator.next(); *    do something for node * }  */public class BSTIterator {    private ArrayList<TreeNode> arr = new ArrayList<TreeNode>();    private int pos = -1;        //@param root: The root of binary tree.    private void inorder(TreeNode root) {        if (root != null) {            inorder(root.left);            arr.add(root);            inorder(root.right);        }    }    public BSTIterator(TreeNode root) {        inorder(root);        if (arr.size() > 0) {            pos = 0;        }    }    //@return: True if there has next node, or false    public boolean hasNext() {        return pos >= 0 && pos < arr.size();    }        //@return: return next node    public TreeNode next() {        return arr.get(pos++);    }}


此外,Chapter之外的二叉树还有这么一些题目:

175. Invert Binary Tree

反转二叉树,HomeBrew的创始人就是倒在了这道题下,用递归做很简单,先把根节点的左右子树对调,然后再递归得对左右子树调用递归。递归返回条件就是当前节点为空。

    public void invertBinaryTree(TreeNode root) {        if (root == null) {            return;        }        TreeNode tmp = root.left;        root.left = root.right;        root.right = tmp;                invertBinaryTree(root.left);        invertBinaryTree(root.right);    }

480. Binary Tree Paths

要求返回所有从根节点到叶子节点的路径。这种要求所有路径的,一看就基本知道八九成是用DFS来做了:

    private void dfs(List<String> res, String path, TreeNode root) {        if (root.left == null && root.right == null) {            path += root.val;            res.add(path);            return;        }        if (root.left != null) {            dfs(res, path + root.val + "->", root.left);        }        if (root.right != null) {            dfs(res, path + root.val + "->", root.right);        }    }    public List<String> binaryTreePaths(TreeNode root) {        List<String> res = new ArrayList();        if (root == null) {            return res;        }        dfs(res, "", root);        return res;    }


245. Subtree

判断一棵树A是否包含另一棵树B,用DFS遍历A的每个节点,对于A的每个节点,调用一个equal函数判断A的这个节点的子树和B树是否完全相等。

        private void dfs(TreeNode T1, TreeNode T2) {        if (T1 != null) {            if (equal(T1, T2)) {                flag = true;                return;            }            dfs(T1.left, T2);            dfs(T1.right, T2);        }    }    public boolean isSubtree(TreeNode T1, TreeNode T2) {        if (T2 == null) {            return true;        }        dfs(T1, T2);        return flag;    }    private boolean equal(TreeNode T1, TreeNode T2) {        // 两个都为空        if (T1 == null && T2 == null) {            return true;        }        // 只有一个为空        if (T1 == null || T2 == null) {            return false;        }        // 都不空,且不相等的时候,就返回false        if (T1.val != T2.val) {            return false;        }        // 相等,则进一步判断        return equal(T1.left, T2.left) && equal(T1.right, T2.right);    }

453. Flatten Binary Tree to Linked List

要求把一棵树按照先根遍历的规则,转换为一个只有右子树的数:

              1               \     1          2    / \          \   2   5    =>    3  / \   \          \ 3   4   6          4                     \                      5                       \                        6
    private TreeNode p = null;    private void inorder(TreeNode root) {        if (root != null) {            if (p != null) {                p.right = root;                p.left = null; <span style="font-family: Arial, Helvetica, sans-serif;">// 这一行代码不能少!</span>            }            p = root;            TreeNode r = root.right; // 这一行代码不能少!                        inorder(root.left);            inorder(r);        }    }    public void flatten(TreeNode root) {        inorder(root);    }
注意每次遍历是把上个节点和当前节点建立联系。如果上个节点存在,则直接把上个节点的右子树指向当前节点。然后把p指向当前节点,并把右子树先拿出来(这点很重要,不拿出来基本就是stackoverflow了),再对左右子树分别进行子递归。


177. Convert Sorted Array to Binary Search Tree With Minimal Height

把一个有序数组转换为一颗高度最小的二叉搜索树。思路很简单,递归建树,每次递归都选择数组的中点建树。

    private TreeNode build(int[] arr, int start, int end, TreeNode root) {        if (start <= end) {            int mid = start + (end - start) / 2;            root = new TreeNode(arr[mid]);            root.left = build(arr, start, mid - 1, root.left);            root.right = build(arr, mid + 1, end, root.right);        }        return root;    }    public TreeNode sortedArrayToBST(int[] A) {          TreeNode root = null;        root = build(A, 0, A.length - 1, root);        return root;    } 


140. Fast Power

Calculate the an % b where a, b and n are all 32bit integers.

For 231 % 3 = 2

For 1001000 % 1000 = 0

首先可以参考下百度百科里对于取模运算的定义:http://baike.baidu.com/view/4887065.htm

我们发现,取模运算有这么些规律:

(a * b) % p = (a % p * b % p) % p


    public int fastPower(int a, int b, int n) {        if (n == 1) {            return a % b;        }        if (n == 0) {            return 1 % b;        }        long res = fastPower(a, b, n / 2);        res = res * res % b;        if (n % 2 == 1) {            res = res * a % b % b;        }        return (int)res;    }

428. Pow(x, n)

这道题与上面那道题有异曲同工之妙,不过推导公式没有上面那么复杂了。也是分治法,需要考虑n小于0的情况,还有分奇偶的情况。如果用分治法则时间复杂度是O(logn),如果是直接用从n递归到n-1再递归到n-2···这种方法,则时间复杂度是O(N)

    public double myPow(double x, int n) {        if (n == 0) {            return 1.0;        }        if (n < 0) {            return 1.0 / myPow(x, -1 * n);        }        double half = myPow(x, n / 2);        if (n % 2 == 1) {            return x * half * half;        }        return half * half;    }

3 0