Hot100 LeetCode(三)

1. 求根到叶子节点数字之和(dfs、bfs)

求根到叶子节点数字之和(leetcode有2道相同的该题) :
https://leetcode-cn.com/problems/sum-root-to-leaf-numbers/
https://leetcode-cn.com/problems/3Etpl5/
这道题第一次没有想出来解法,看了题解,发现还是很巧妙。 重要的点包含以下几个 :

1.该节点的值应该是 父节点(也是累计值)值*10 + 该节点的值。
2.构建一个递归函数,第一个参数是该节点,第二个参数是父节点的值。
3.可以理解根节点的父节点值是0 。

明白了这3点,就可以开始进行深度优先搜索了。 我画了一个图,看到这个图,可能会更加帮助理解以上3点。
深度优先搜索思路

看懂了以上的思路后,代码就很好写了,如下 :

class Solution {
    private int dfs(TreeNode c, int prevSum){
        if(c == null){
            return 0; 
        }
        int sum =  c.val + prevSum*10 ; 
        //叶子节点,直接返回值
        if (c.left == null && c.right == null){
            return sum ; 
        }
        //非叶子节点,返回左右子孩子的和
        else {
            return dfs(c.left , sum) + dfs(c.right, sum) ; 
        }
    }
    public int sumNumbers(TreeNode root) {
       return dfs(root,0) ; 
    }
}

2. 二叉树的最近公共祖先(dfs)

二叉树的最近公共祖先(两道同样的题) :
https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-tree/
https://leetcode-cn.com/problems/er-cha-shu-de-zui-jin-gong-gong-zu-xian-lcof/
这道题的难度也是很大,自己做的时候依然没想到解法。(悲剧!!),看了题解,勉强理解了解法。这里有个巧妙的转换,就是最近的公共祖先 可以提炼成以下几个特征 :

若 root 是 p, q 的 最近公共祖先 ,则只可能为以下情况之一:
1.p 和 q 在 root的子树中,且分列 root的异侧(即分别在左、右子树中);
2.p = root ,且 q 在 root 的左或右子树中;
3.q = root ,且 p 在 root 的左或右子树中;

解释一下上边说的性质,看下下边的例子树 :



节点2和节点5都是7,4的公共祖先 ; 但是7,4分属节点2的两侧,而属于节点5的右侧,那么最近公共祖先是2,而不是5。
根据三个特征,不难得到如下代码 :

class Solution {

    /**
     * 在以c为根节点的树内,递归查找节点p,也就是确认节点p是否在这颗以c为根节点的树内。
     */
    private boolean findNodeRecursive(TreeNode c , TreeNode p){
        if(c == null) return false ;
        //判断根节点
        if(p.val == c.val){
            return true ;
        }
        //如果根节点不是p,那么递归查看左右子树
        return findNodeRecursive(c.left, p) || findNodeRecursive(c.right,p) ;
    }
    
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        //如果给了个空树,返回NULL
        if(root == null){
            return null ;
        }
        //如果给定的p或者q是根节点,那么根节点就是最近公共祖先(显而易见的结论)
        if(root == p || root == q){
            return root;
        }

        //如果节点p和q都在 root的左子树中,那么p和q的最近公共祖先一定在root的左子树内
        if(findNodeRecursive(root.left,p) && findNodeRecursive(root.left,q)){
            return lowestCommonAncestor(root.left,p,q) ;
        }

        //如果节点p和q都在 root的右子树中,那么p和q的最近公共祖先一定在root的右子树内
        if(findNodeRecursive(root.right,p) && findNodeRecursive(root.right,q)){
            return lowestCommonAncestor(root.right,p,q) ;
        }

        //如果上边都不符合,证明p和q分别在root的左右子树(也就是异侧),那root就是最近公共祖先了
        return root ; 
    }
}

3. 二叉搜索树的最近公共祖先

二叉搜索树的最近公共祖先 (该题目有两道重复题):
https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-search-tree/
https://leetcode-cn.com/problems/er-cha-sou-suo-shu-de-zui-jin-gong-gong-zu-xian-lcof/

相比于上一道题,该题更简单,首先,就要了解一下二叉搜索数的概念了。 通过下边的概念,很容易发现,二叉搜索树是有大小顺序的,这样会降低题目难度。

二叉查找树(Binary Search Tree),(又:二叉搜索树,二叉排序树)它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉查找树。

同样是最近公共祖先,那么也是满足那个条件的。只不过,这里因为有大小排序,更简单了。因为更的p和q一定在树中。所以,这里通过节点的val值就能判断p、q在root的节点的左子树还是右子树了,不需要上一道题中,做一个findNodeRecursive(TreeNode c , TreeNode p)函数了。如果看到了第2道题目,这题也就很简单了,下边是我的代码:

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        //如果是空树,返回空值
        if(root == null){
            return null ; 
        }

        //如果p、q中有一个节点已经是根节点,那么最近公共祖先就是该节点
        if(root.val == p.val || root.val == q.val){
            return root ;
        }

        //如果p、q都在root的左子树内,那么在root的左子树递归
        if(p.val < root.val && q.val < root.val){
            return lowestCommonAncestor(root.left,p,q) ;
        }

        //如果p、q都在root的右子树内,那么在root的右子树递归
        if(p.val > root.val && q.val > root.val){
            return lowestCommonAncestor(root.right,p,q) ;
        }

        //否则p、q落到了root的左右两边,那么root就是最近公共祖先
        return root ;
        
    }
}

4. 从二叉树的遍历结果还原二叉树

通过遍历结果构造二叉树,是手工计算中经常出现的题目,现在用程序来还原。
从前序与中序遍历序列构造二叉树 : https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/solution/
根据前序和后序遍历构造二叉树 :https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-postorder-traversal/
从中序与后序遍历序列构造二叉树 : https://leetcode-cn.com/problems/construct-binary-tree-from-inorder-and-postorder-traversal/
做题最初,被“还原/构造二叉树”给难住了,没有想出如何来构造二叉树,看了题解,发现其实简单,就是new一个TreeNode对象作为root节点,并指定好该对象的root.left和root.right属性即可,最终返回root节点。

5. TOP高频词统计 :

leetcode地址: https://leetcode-cn.com/problems/top-k-frequent-elements/
下边是我的代码 :

class Solution {
    public int[] topKFrequent(int[] nums, int k) {
        // 构建每个数字出现频次的Map    
        Map basNum = new HashMap<>() ;
        for(int i=0 ; i pq = new PriorityQueue<>(new Comparator() {
            @Override
            public int compare(int[] o1, int[] o2) {
                return o2[1] - o1[1];
            }
        });  // 注意大顶堆不是默认,需要重新定义compare方法,默认是o1-o2,这里降序所以改为o2-o1了

        // 加入到堆中去
        for (Map.Entry bas : basNum.entrySet() ) {   //注意map的for循环方式
            int[] tt = {bas.getKey(), bas.getValue()} ;  //注意数组的初始化方法
            pq.add(tt) ;
        }
        int[] ans = new int[k] ;
        for (int i=0 ; i

你可能感兴趣的:(Hot100 LeetCode(三))