1. 求根到叶子节点数字之和(dfs、bfs)
求根到叶子节点数字之和(leetcode有2道相同的该题) :
https://leetcode-cn.com/problems/sum-root-to-leaf-numbers/
https://leetcode-cn.com/problems/3Etpl5/
这道题第一次没有想出来解法,看了题解,发现还是很巧妙。 重要的点包含以下几个 :
明白了这3点,就可以开始进行深度优先搜索了。 我画了一个图,看到这个图,可能会更加帮助理解以上3点。1.该节点的值应该是 父节点(也是累计值)值*10 + 该节点的值。
2.构建一个递归函数,第一个参数是该节点,第二个参数是父节点的值。
3.可以理解根节点的父节点值是0 。
看懂了以上的思路后,代码就很好写了,如下 :
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