leetcode hot100_part08_二叉树(完)

关于二叉树的一些基本遍历模版就不说了

94.二叉树中序遍历

2/29-10/23

已经忘完了,前中后序遍历指的是根节点的顺序;注意根节点判空

在这里有个问题,ArrayList是定义的包装类,而add的是int类型,得益于Java的自动装箱(大佬勿喷)。 空间时间都是O(n)。

埋坑:迭代方法和Morris 中序遍历

105.从前序和中序序列构造二叉树

2/29

        根据前序和中序或者后序和中序才能复原二叉树,要恢复二叉树必须知道中序序列,只是知道前序和后序,不能恢复二叉树,因为不知道中序序列无法获知根节点的左右子树位置。

        还是看题解完成的,结果输出树的根节点,应该就是这个树的层序遍历,root是根节点,一开始还没特别明白,好像也不是层序遍历。题目的要求是构造二叉树返回根节点。

class Solution {private Map<Integer, Integer> indexMap;public TreeNode buildTree(int[] preorder, int[] inorder) {int n = preorder.length;//hash映射indexMap = new HashMap<Integer,Integer>();for(int i = 0; i < n; i++){indexMap.put(inorder[i],i);}return getroot(preorder, 0, n-1, inorder, 0, n-1);}//前序遍历的第一个元素在中序遍历中定位,左右部分再递归private TreeNode getroot(int[] preorder, int pre_start, int pre_end, int[] inorder, int in_start, int in_end){if(pre_start > pre_end){return null;}//得到前序第一个元素在中序中的下标int in_index = indexMap.get(preorder[pre_start]);//定义根节点TreeNode root  = new TreeNode(preorder[pre_start]);//左子树长度int left_Subtree_size = in_index - in_start;//圈出两个序列中的左子树root.left = getroot(preorder, pre_start+1, pre_start + left_Subtree_size, inorder, in_start, in_index -1);//圈出两个序列中的右子树root.right = getroot(preorder, pre_start + left_Subtree_size + 1, pre_end,inorder, in_index + 1, in_end );return root;}
}

day02

 104.二叉树的最大深度easy√

看到题目最先想到dfs,深度优先搜索的数据结构为栈(stack)。在每次遍历到达叶子节点的时候,为当前最长路径并更新结果, 关键是到达叶子节点后的做法,附上自己的代码

class Solution {private int maxDepth = 0;private int current_maxDepth = 0;public int maxDepth(TreeNode root) {Traverse(root);return maxDepth;}private void Traverse(TreeNode root){if(root != null){current_maxDepth++;Traverse(root.left);Traverse(root.right);current_maxDepth--;} else{if(current_maxDepth > maxDepth)maxDepth = current_maxDepth;//current_maxDepth = 0;}}}

还是递归,三种不同顺序的遍历其实都是dfs,每进入一层递归,深度加一。如果当前节点为null,说明遍历到了叶子节点,这时更新最大深度。不可以在更新之后马上置零,首先置零就是不对,毕竟递归返回时深度是逐渐减一,应该在遍历完右子树的时候减一,也就是弹栈的时候,更简明的说,深度减一的时候应该发生在当前层遍历完的时候。

官方解法

递归,最大深度是左右子树的最大深度+1

102.二叉树的层序遍历Medium

有点印象,要用队列,和一般的BFS不同的是,这里记录每层节点的个数,更够出队节点个数个元素。

  • 首先根元素入队
  • 当队列不为空的时候
    1. 求当前队列的长度 si
    2. 依次从队列中取 si个元素进行拓展,然后进入下一次迭代
class Solution {public List<List<Integer>> levelOrder(TreeNode root) {//结果集List<List<Integer>> res = new ArrayList<>();//每次都忘记这个空条件if(root == null){return res;}Queue<TreeNode> queue = new LinkedList<>();queue.offer(root);while(!queue.isEmpty()){//定义一个集合存放每层元素List<Integer> level_ret = new ArrayList<>();int levelLength = queue.size();for(int i = 0; i < levelLength; i++){TreeNode node = queue.poll();level_ret.add(node.val);//又忘记判空if(node.left != null){queue.offer(node.left);}if(node.right != null){queue.offer(node.right);}}res.add(level_ret);}return res;}
}

对Queue和相关API不熟悉

day03

199.二叉树的右视图Medium

看到题目后想到的就是昨天的层序遍历,直接在每层的最后一个节点处将该节点添加到集合中。

class Solution {public List<Integer> rightSideView(TreeNode root) {//结果集合List<Integer> res = new ArrayList<>();//判空if(root == null)return res;Queue<TreeNode> queue = new LinkedList<>();queue.offer(root);while(!queue.isEmpty()){int currenr_level_Length = queue.size();for(int i = 0; i < currenr_level_Length; i++){TreeNode node = queue.poll();if(i == currenr_level_Length - 1){res.add(node.val);}if(node.left != null){queue.offer(node.left);}if(node.right !=null){queue.offer(node.right);}}}return res;}
}

 第一次写有2点小错误,记一下:

  1. 定义队列的时候没有说明类型,后面出队操作存储到node中时类型不能转换
  2. 等于判断时是双等于
  3. 判空的时候,如果说先判空返回的结果怎么都不对,先定义结果集合,root空就直接返回

题解里的DFS看一下,下次可以用这个方法:

class Solution {List<Integer> res = new ArrayList<>();public List<Integer> rightSideView(TreeNode root) {dfs(root, 0); // 从根节点开始访问,根节点深度是0return res;}private void dfs(TreeNode root, int depth) {if (root == null) {return;}// 先访问 当前节点,再递归地访问 右子树 和 左子树。if (depth == res.size()) {   // 如果当前节点所在深度还没有出现在res里,说明在该深度下当前节点是第一个被访问的节点,因此将当前节点加入res中。res.add(root.val);}depth++;dfs(root.right, depth);dfs(root.left, depth);}
}

这个方法的遍历顺序和先序遍历的左右顺序正好相反,为根右左,这样就可以保证每次第一个访问到的是该层最右边的元素。res中的结果元素和深度对应,每层一个。目前还没怎么做DFS的题。

114.二叉树展开为链表Medium

 二叉树展开为链表 - 力扣(LeetCode),可以看一下这个题解。方法很多,感觉首先就理解错了题目的意思,要求是展开,应该是原地算法,你自己再构造一个不行。也行,就像题解那样获取前序序列后从根节点构造,你是又搞了个根节点,看清题目

看了题解就先用最简单的方法吧:

class Solution {List<TreeNode> pre_res= new ArrayList<>();public void flatten(TreeNode root) {preorder(root);TreeNode node = new TreeNode();node = root;int length = pre_res.size();for(int i = 1; i < pre_res.size(); i++){node.right = pre_res.get(i); node.left = null;node = node.right;}return ;}private void preorder(TreeNode root){if(root == null)return ;pre_res.add(root);preorder(root.left);preorder(root.right);}
}

与官方主要的不同在for循环里,官方是拿到两个元素进行的操作,当时还不明白怎么返回的,应该是根据根节点的地址来判定的,就看这个地址存储的内容。

class Solution {public void flatten(TreeNode root) {List<TreeNode> list = new ArrayList<TreeNode>();preorderTraversal(root, list);int size = list.size();for (int i = 1; i < size; i++) {TreeNode prev = list.get(i - 1), curr = list.get(i);prev.left = null;prev.right = curr;}}public void preorderTraversal(TreeNode root, List<TreeNode> list) {if (root != null) {list.add(root);preorderTraversal(root.left, list);preorderTraversal(root.right, list);}}
}

这题磨磨蹭蹭的搞了好久,注意效率不会的及时看答案。 

day04

108.将有序数组转化为二叉搜索树

BST:

二叉搜索树(BST,Binary Search Tree),也称二叉排序树或二叉查找树。
二叉搜索树:一棵二叉树,可以为空;如果不为空,满足以下性质:

  1. 非空左子树的所有键值小于其根结点的键值。
  2. 非空右子树的所有键值大于其根结点的键值。
  3. 左、右子树都是二叉搜索树。

首先,了解二叉搜索树BST及高度平衡二叉搜索树AVL,看了两分钟b站的视频有了思路,这题和前面做过的根据前序和中序构造二叉树已经种种分治类题目很像,有了思路自己基本能写出来:

因为数组是有序的,要求构造高度平衡的BST,因此我们找到数组的中间节点作为根节点,进行数组的划分,然后再根据左右区间进行相同的递归操作。构造时递归调用返回的是节点值,与遍历时不同。

class Solution {//private TreeNode root;public TreeNode sortedArrayToBST(int[] nums) {int length = nums.length;return buildSubAVL(nums, 0, length-1);//return root;}private TreeNode buildSubAVL(int[] nums, int start, int end){if(start > end){return null;}int index = (start + end)/2;TreeNode root = new TreeNode();root.val = nums[index];root.left = buildSubAVL(nums, start, index-1);root.right = buildSubAVL(nums, index + 1, end);return root;}
}

原来的判空条件是这样写的,结果超时,栈溢出了。

if(start == end){return new TreeNode(nums[start]);
}

230.二叉搜索树中第K小的元素

递归法完全遍历

根据BST性质,对其中序遍历得到的就是树中元素值递增的排列,能直接得到其中第K小的元素。

class Solution {private List<TreeNode> inorder = new ArrayList<>();public int kthSmallest(TreeNode root, int k) {inorderTraverse(root);return inorder.get(k-1).val;}private void inorderTraverse(TreeNode root){if(root == null)return;inorderTraverse(root.left);inorder.add(root);inorderTraverse(root.right);  }
}

刚想在遍历到第K个元素的时候进行return,不行好像因为它还在递归的过程中,return之后还是在函数里面。 

迭代法不完全遍历

有进阶要求:如果BST频繁变化,比如频繁的插入删除等,每次查找都要遍历效率不高

视频二叉树中序遍历迭代,抓住访问的顺序和要处理的顺序是否一致,

右孩子为空弹栈,到上一层,很像前面的一题,附上迭代中序遍历的代码,结合迭代的ppt理解一下吧

class Solution {public List<Integer> inorderTraversal(TreeNode root) {List<Integer> res = new ArrayList<Integer>();Deque<TreeNode> stk = new LinkedList<TreeNode>();while (root != null || !stk.isEmpty()) {while (root != null) {stk.push(root);root = root.left;}root = stk.pop();res.add(root.val);root = root.right;}return res;}
}

 那关于这一题也就是在弹栈的时候计数,也就是处理的时候记录是第几个处理的,本来想在递归中写的,好像写不出来?

class Solution {public int kthSmallest(TreeNode root, int k) {Deque<TreeNode> stack = new ArrayDeque<TreeNode>();while (root != null || !stack.isEmpty()) {while (root != null) {stack.push(root);root = root.left;}root = stack.pop();--k;if (k == 0) {break;}root = root.right;}return root.val;}
}

day05

226.翻转二叉树

这题比较简单,就不贴代码了,主要是要注意不能中序遍历,可以想象一棵最简单的二叉树,首先是遍历完左孩子,然后执行交换左右孩子,再去遍历右孩子,这时遍历的右孩子其实是没遍历前的左孩子,如果左孩子还有孩子那么在根节点翻转之前已经遍历过了,翻转之后再遍历翻转相当于没翻转。就这样吧,写的很明白了。

98.验证二叉搜索树

根据二叉搜索树的性质吧,中序遍历之后一定是递增数组序列。拿到中序结果后一个个比较,这应该是最笨的方法。不贴代码了,主要是写的时候注意判断节点值相等的情况。

也看了题解,本来自己也想到用两个变量来比较而不像都存储在数组里那样占空间,但是自己不懂Long.min和long.max这种。贴个官方递归的代码

class Solution {public boolean isValidBST(TreeNode root) {return isValidBST(root, Long.MIN_VALUE, Long.MAX_VALUE);}public boolean isValidBST(TreeNode node, long lower, long upper) {if (node == null) {return true;}if (node.val <= lower || node.val >= upper) {return false;}return isValidBST(node.left, lower, node.val) && isValidBST(node.right, node.val, upper);}
}

顺便复习一下中序的迭代方法

class Solution {public boolean isValidBST(TreeNode root) {Deque<TreeNode> stack = new LinkedList<TreeNode>();double inorder = -Double.MAX_VALUE;while (!stack.isEmpty() || root != null) {while (root != null) {stack.push(root);root = root.left;}root = stack.pop();// 如果中序遍历得到的节点的值小于等于前一个 inorder,说明不是二叉搜索树if (root.val <= inorder) {return false;}inorder = root.val;root = root.right;}return true;}
}

题解还有很多方法和思想,留个坑吧。

437.路径总和 III

这题是medium,自己ac了,但是是笨法子,看题目肯定是要遍历完所有路径的,2点要求:路径只能往下走,路径开头不一定是根节点。首先想到前序遍历,对每个节点的访问时机就是处理时机,

  1. 嵌套进行递归,外层的递归遍历是遍历每个节点为路径的起始节点,内层的递归遍历是对于固定起始的根节点进行路径遍历
  2. 还是什么时候进行递归弹栈(路径和减去当前节点路径)的问题,遍历完右节点。这个点第三次遇到了,这个和官方的嵌套递归还不一样。
  3. 路径和可能会超过int,要定义为long(第127个测试用例)

贴个自己的代码:

双重递归遍历所有情况

class Solution {private int routeNum = 0;private int targetSum = 0; public int pathSum(TreeNode root, int targetSum) {this.targetSum = targetSum;preorder(root);return routeNum;}private void preorder(TreeNode root) {if(root == null)return;//long curLenth = 0;sure_node_get(root,curLenth);preorder(root.left);preorder(root.right);}private void sure_node_get(TreeNode node, long curLenth) {if(node == null)return;curLenth = curLenth + node.val;if(curLenth == targetSum)routeNum++;sure_node_get(node.left, curLenth);sure_node_get(node.right, curLenth);curLenth = curLenth - node.val;}
}

官方的,很巧妙:

class Solution {public int pathSum(TreeNode root, int targetSum) {if (root == null) {return 0;}int ret = rootSum(root, targetSum);ret += pathSum(root.left, targetSum);ret += pathSum(root.right, targetSum);return ret;}public int rootSum(TreeNode root, int targetSum) {int ret = 0;if (root == null) {return 0;}int val = root.val;if (val == targetSum) {ret++;} ret += rootSum(root.left, targetSum - val);ret += rootSum(root.right, targetSum - val);return ret;}
}

前缀和+DFS:

        上面那种方法要递归遍历所有的情况有点浪费时间,而且有的路径长度重复计算了。既然要找到一条起始节点可以不是根节点的固定长度路径,可以用作差的方法。

        例如一个一维数组,我们要找到连续子数组的和为固定值的子数组(好像有这道题目),定义两个以数组第一个元素开头的动态连续子数组,对每个子数组求和作差。在这道题中也是一样的道理,二叉树从根节点到某个子节点的路径是唯一的。

        所以这个看了题解已经众多评论之后我认为有以下几点需要重点理解:

  1. 前缀和定义:本题是从根节点到遍历到的当前节点的路径上所有元素之和,包括根节点。也就是说每个节点都有自己的前缀和。
  2. 前缀和的存储:采用hashmap,key值为不同节点的前缀和的值,value为该前缀和的值出现次数;更具体一点,我认为是从根节点到遍历到的当前节点的位置这条唯一路径上某个具体的前缀和的值出现的次数。
  3. 整体流程和所谓的“状态恢复”:采用dfs遍历树,首先初始化map集合。从根节点开始,每遍历到一个节点:
    • 首先计算当前节点的前缀和,
    • 然后看看集合中是否又满足条件的前缀和(集合中是否存在前缀和的值为当前节点前缀和减去所求路径长度)
    • 将当前缀和的信息更新or添加到map集合
    • 递归遍历左右子树
    • 关于最后的状态恢复,其实就是上面说的提到很多次的弹栈恢复,因为只遍历了整个数一次,而且要求所求路径必须向下,我们计算时也以根节点到某个节点的一条也只有一条路径上去计算。因此这个前缀和其实和你自己想的那个解法的路径是一个东西。都需要弹栈,该节点左右子树遍历完后,也标志着该节点的遍历完成,所以要在集合中减去一次该节点的前缀和。

写了好多,有点烦了,贴代码自己理解吧:

这篇文章在ipad题解评论看到了但是在电脑上没找到。

class Solution {public int pathSum(TreeNode root, int targetSum) {Map<Long, Integer> prefix = new HashMap<Long, Integer>();prefix.put(0L, 1);return dfs(root, prefix, 0, targetSum);}public int dfs(TreeNode root, Map<Long, Integer> prefix, long curr, int targetSum) {if (root == null) {return 0;}int ret = 0;curr += root.val;ret = prefix.getOrDefault(curr - targetSum, 0);prefix.put(curr, prefix.getOrDefault(curr, 0) + 1);ret += dfs(root.left, prefix, curr, targetSum);ret += dfs(root.right, prefix, curr, targetSum);prefix.put(curr, prefix.getOrDefault(curr, 0) - 1);return ret;}
}

Java高级之HashMap中的put()方法和putIfAbsent()方法_hashmap putifabsent-CSDN博客

Java HashMap getOrDefault() 方法 | 菜鸟教程 (runoob.com)

day06

124.二叉树中的最大路径和Hard

        以为想到了却又没想到,最后还是屎山代码憋出来了。这道hard说难也不难。分析题目,主要是路径,这个路径可以是跨越根节点的,也就是可以左根右这种,之前做的遍历题目都是从根节点出发不会出现横跨根节点的路径。

        对于二叉树类的复杂题目,好像还是先考虑最简单的二叉树情况然后递归,因此如果是最简单的三个节点的二叉树,它的最大路径和都有6种,三个节点和三个组合(根+左,根+右,左+根+右),我们需要分类讨论,这也是DP(dynamic programing)的一个重要思想。

        根据之前的经验,我们分类成从根节点向下的路径(不跨越根节点)和跨越根节点的路径,说个废话,这里是一定要包含根节点的,因为递归中每个点都是被看做根节点进行遍历的。如果我们知道了左右子树的MRL(max route length最大路径和),那么自然而然的就会去思考以根节点的二叉树的MRL;

        也就是,把遍历到的根节点代表的子树的作用抽象成一个节点,官方题解里为什么要和0比较也是这个意思,那么就分类讨论吧,自己的方法中对于跨越根节点的路径和单独存放在集合,后面再去比较,也是没有进化完全。

class Solution {List<Integer> maybe_res = new ArrayList<>(); public int maxPathSum(TreeNode root) {int max1 = curr_node_start_Max(root);int max2 = Collections.max(maybe_res);return Math.max(max1, max2);}//以当前节点为头的最大路径和,向下private int curr_node_start_Max(TreeNode root) {if(root == null)return 0;int leftMax = curr_node_start_Max(root.left);int rightMax = curr_node_start_Max(root.right);int x = Math.max(leftMax, rightMax);if(root.val < 0) {//针对只有-3的样例if(root.left != null)maybe_res.add(leftMax);if(root.right != null)maybe_res.add(rightMax);//maybe_res.add(x);maybe_res.add(root.val + leftMax + rightMax);//原来这个地方是直接返回root.val的//后来[8,9,-6,null,null,5,9]这个样例没过才改的return Math.max(root.val, root.val + x);} //if(root.val >= 0) else{if(leftMax>=0&&rightMax>=0){maybe_res.add(root.val+leftMax+rightMax);return root.val + x;} else if(x <0){//如果左右子树的MRL都小于0,不如一个只要根节点return root.val;                }else{return root.val + x;}}}
}

像一坨,但是思路是有点模样的

官方题解:

class Solution {int maxSum = Integer.MIN_VALUE;public int maxPathSum(TreeNode root) {maxGain(root);return maxSum;}public int maxGain(TreeNode node) {if (node == null) {return 0;}// 递归计算左右子节点的最大贡献值// 只有在最大贡献值大于 0 时,才会选取对应子节点int leftGain = Math.max(maxGain(node.left), 0);int rightGain = Math.max(maxGain(node.right), 0);// 节点的最大路径和取决于该节点的值与该节点的左右子节点的最大贡献值int priceNewpath = node.val + leftGain + rightGain;// 更新答案maxSum = Math.max(maxSum, priceNewpath);// 返回节点的最大贡献值return node.val + Math.max(leftGain, rightGain);}
}

很巧妙,官方的这个priceNewpath是在左右子树都遍历完的时候计算的,想想你前面写的代码在右子树遍历完之后的弹栈操作,都是有相通的点,而且也是根左右相加,解决了跨根节点的问题,其实这里就是和自己的把跨根节点的MRL存到集合里一样,人家是及时更新,你是最原始的方法选出最大值。

返回时也只能返回不跨根节点的路径,因为跨的都更新比较过了。就写到这吧,越写越感觉自己的解法和官方有很多相同之处。

236.二叉树的最近公共祖先

分别记录p,q节点的遍历路径然后比较,怎么记录?不会。。好像会了,最后没写出来

看题解了,有两种方法

存储节点父子关系

class Solution {Map<Integer, TreeNode> parent = new HashMap<Integer, TreeNode>();Set<Integer> visited = new HashSet<Integer>();public void dfs(TreeNode root) {if (root.left != null) {parent.put(root.left.val, root);dfs(root.left);}if (root.right != null) {parent.put(root.right.val, root);dfs(root.right);}}public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {dfs(root);while (p != null) {visited.add(p.val);p = parent.get(p.val);}while (q != null) {if (visited.contains(q.val)) {return q;}q = parent.get(q.val);}return null;}
}

这种方法就是先遍历所有节点,可以将所有的父子关系存储在hashmap中,然后直接从其中一个节点p出发找到它的所有父节点并加入到集合中,再一个个查找另一个节点的父节点是否在其中。这种方法还是比较好理解的,之前学的时候好像也接触过这种方法。

递归,分类讨论

咱也不知道这个方法为啥叫递归,所有的遍历方法也用到了递归啊。

        一,对于结果节点的判断条件还是能理解,两种情况,分别是p和q没有父子节点关系,p和q其中一个是另一个的父节点。

        二,对fx函数的定义,以x为根节点的子树中是否包含p和q节点。

        三,对于dfs返回条件的理解,首先触发的一定是遍历到的节点值是p或者q,从lson,rson是递归的返回值也能说明这一点。

class Solution {private TreeNode ans;public Solution() {this.ans = null;}private boolean dfs(TreeNode root, TreeNode p, TreeNode q) {if (root == null) return false;boolean lson = dfs(root.left, p, q);boolean rson = dfs(root.right, p, q);if ((lson && rson) || ((root.val == p.val || root.val == q.val) && (lson || rson))) {ans = root;} return lson || rson || (root.val == p.val || root.val == q.val);}public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {this.dfs(root, p, q);return this.ans;}
}

 可以再理解一下dfs返回值的写法含义,自己再写的时候dfs里root.left能写成root真是服了。

这题拖了挺久,从上周四下午,中间就没leetcode。。。

day07

 剩下的两道easy的二叉树的题目,二叉树也就暂时告一段落

这两个是easy??还是我太菜了,打扰了

101.对称二叉树√

两次遍历比较:

        比较任意两种遍历顺序的颠倒左右子树遍历的结果是否相同,这个方法不行,题目里第二个样例不过的。原因就是空节点影响了判断,在遍历到空节点时不要直接返回,向遍历结果集合中添加一个元素(-101,)来标记空节点。ac了。不贴代码了这个很好写。

对于官方题解先不看迭代方法了,挖坑。。

递归:

        关键是两个节点的左右节点都要判断,以及各种情况的分类

迭代:还是两两节点处理

543.二叉树的直径

        这题也是有点思考的,所以现在easy的标准是代码量还是思路呢?这道题的直径指的是任意两个节点之间最长路径的长度。题目中说的路径不一定经过根节点,根节点不也就是个节点,每个节点也是每次遍历的根节点。那么最长的路径一定是跨域某个节点的,左加右总比单边大的,这题和前面的路径和也像,这里想到二叉树的最大深度这题,稍作修改,遍历到某个节点时,跨域节点的最大路径一定是左右子树最大深度和。

        对于return后的最大深度,其实是左右子树的而不是本节点的,所以不用去掉加一,一开始没想清楚还去掉了,直接不能走出来,lrsum一直是0。不写那么细了。

class Solution {private int lrsum;public int diameterOfBinaryTree(TreeNode root) {lrsum = 0;maxDepth(root);return lrsum ;}private int maxDepth(TreeNode root) {if(root == null){return 0;}int leftHeight = maxDepth(root.left);int rightHeight = maxDepth(root.right);int x = leftHeight + rightHeight;if(x > lrsum)lrsum = x;return Math.max(leftHeight, rightHeight) + 1;}
}

        然后呢,看了官方题解,好好好,原来是一样的,看了就当巩固一下了,特别是求树深度的代码。

        二叉树的部分到这就结束了,那么那么,感觉还有很多要理清的,比如递归是隐式栈?(评论里看到的),遍历的迭代写法,这个是二刷的重点,及时复习吧,及时记录,坚持。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/501253.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

电子电气架构 --- 中央处理器HPC及软件架构

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 所谓鸡汤,要么蛊惑你认命,要么怂恿你拼命,但都是回避问题的根源,以现象替代逻辑,以情绪代替思考,把消极接受现实的懦弱,伪装成乐观面对不幸的…

大模型 LangChain 开发框架:Runable 与 LCEL 初探

大模型 LangChain 开发框架&#xff1a;Runable 与 LCEL 初探 一、引言 在大模型开发领域&#xff0c;LangChain 作为一款强大的开发框架&#xff0c;为开发者提供了丰富的工具和功能。其中&#xff0c;Runnable 接口和 LangChain 表达式语言&#xff08;LCEL&#xff09;是构…

Flash Attention V3使用

Flash Attention V3 概述 Flash Attention 是一种针对 Transformer 模型中注意力机制的优化实现&#xff0c;旨在提高计算效率和内存利用率。随着大模型的普及&#xff0c;Flash Attention V3 在 H100 GPU 上实现了显著的性能提升&#xff0c;相比于前一版本&#xff0c;V3 通…

《Vue3实战教程》34:Vue3状态管理

如果您有疑问&#xff0c;请观看视频教程《Vue3实战教程》 状态管理​ 什么是状态管理&#xff1f;​ 理论上来说&#xff0c;每一个 Vue 组件实例都已经在“管理”它自己的响应式状态了。我们以一个简单的计数器组件为例&#xff1a; vue <script setup> import { r…

电脑找不到mfc110.dll文件要如何解决?Windows缺失mfc110.dll文件快速解决方法

一、mfc110.dll文件的重要性 mfc110.dll&#xff0c;全称Microsoft Foundation Class Library 110&#xff0c;是Microsoft Visual C Redistributable for Visual Studio 2012的一部分。这个动态链接库&#xff08;DLL&#xff09;文件对于支持基于MFC&#xff08;Microsoft F…

OSPF特殊区域(open shortest path first LSA Type7)

一、区域介绍 1、Stub区域 Stub区域是一种可选的配置属性。通常来说&#xff0c;Stub区域位于自治系统的边界&#xff0c;例如&#xff0c;只有一 个ABR的非骨干区域。在这些区域中&#xff0c;设备的路由表规模以及路由信息传递的数量都会大量减少。 kill 4 5类type 传递1 …

浏览器选中文字样式

效果 学习 Chrome: 支持 ::selection。Firefox: 支持 :-moz-selection 和 ::selection。Safari: 支持 ::selection。Internet Explorer: 支持 :-ms-selection。Microsoft Edge: 支持 ::-ms-selection 和 ::selection。 代码 <!DOCTYPE html> <html lang"en&qu…

Rabbitmq追问1

如果消费端代码异常&#xff0c;未手动确认&#xff0c;那么这个消息去哪里 2024-12-31 21:19:12 如果消费端代码发生异常&#xff0c;未手动确认&#xff08;ACK&#xff09;的情况下&#xff0c;消息的处理行为取决于消息队列的实现和配置&#xff0c;以下是基于 RabbitMQ …

Ansys Discovery 中的网格划分方法:探索模式

本篇博客文章将介绍 Ansys Discovery 中可用于在探索模式下进行分析的网格划分方法。我们将在下一篇博客中介绍 Refine 模式下的网格划分技术。 了解 Discovery Explore 模式下的网格划分 网格划分是将几何模型划分为小单元以模拟系统在不同条件下的行为的过程。这是通过创建…

Golang的并发编程实战经验

## Golang的并发编程实战经验 并发编程是什么 并发编程是指程序的多个部分可以同时执行&#xff0c;这样可以提高程序的性能和效率。在Golang中&#xff0c;并发编程是通过goroutine来实现的&#xff0c;goroutine是一种轻量级线程&#xff0c;可以在一个程序中同时运行成千上万…

vue2实现excel文件预览

一、插件 通过xlsx插件解析excel数据&#xff0c;对解析后的html组件进行渲染展示。 npm install xlsx 二、完整代码 <template><!-- excel文件预览 --><divelement-loading-text"拼命加载中"element-loading-spinner"el-icon-loading"…

低代码引擎插件开发:开启开发的便捷与创新之路

OneCode授权演示 一、低代码引擎与插件开发的概述 在当今快节奏的软件开发领域&#xff0c;低代码引擎正逐渐崭露头角。低代码引擎旨在让开发人员能够以最少的代码量创建功能丰富的应用程序&#xff0c;而其中的关键组成部分便是插件开发。低代码引擎通过提供可视化的开发环境…

Golang的代码质量分析工具

Golang的代码质量分析工具 一、介绍 作为一种高效、简洁、可靠的编程语言&#xff0c;被越来越多的开发者所喜爱和采用。而随着项目规模的增长和团队人员的扩大&#xff0c;代码质量的管理变得尤为重要。为了保障代码的可维护性、健壮性和可扩展性&#xff0c;我们需要借助代码…

JVM实战—9.线上FGC的几种案例

大纲 1.如何优化每秒十万QPS的社交APP的JVM性能(增加S区大小 优化内存碎片) 2.如何对垂直电商APP后台系统的FGC进行深度优化(定制JVM参数模版) 3.不合理设置JVM参数可能导致频繁FGC(优化反射的软引用被每次YGC回收) 4.线上系统每天数十次FGC导致频繁卡顿的优化(大对象问题…

蓝耘平台使用InstantMesh‌生成高质量的三维网格模型!3D内容创作!小白入门必看!!!

目录 引言 InstantMesh应用介绍 蓝耘平台与InstantMesh结合使用 如何部署&#xff08;超简单&#xff09; 第一步登录蓝耘平台 第二步点击应用商城 ​编辑 第三步选择InstantMesh 第四步点击部署 第五步点击快速启动应用 第六步即可体验该产品 总结 注册链接 引言…

LeetCode:106.从中序与后序遍历序列构造二叉树

跟着carl学算法&#xff0c;本系列博客仅做个人记录&#xff0c;建议大家都去看carl本人的博客&#xff0c;写的真的很好的&#xff01; 代码随想录 LeetCode&#xff1a;106.从中序与后序遍历序列构造二叉树 给定两个整数数组 inorder 和 postorder &#xff0c;其中 inorder …

aardio —— 虚表 —— 模拟属性框

写了个简单的属性框例程&#xff0c;抛砖引玉&#xff0c;期待你做出更丰富强大的功能。 可折叠行、可输入文本、可下拉选择、支持下拉选择图片、颜色等功能。 只有想不到&#xff0c;没有做不到&#xff0c;发挥你的想象力吧。 import win.ui; import godking.comboboxEx im…

word文档中的文档网格——解决相同行间距当显示出不同行间距的情况

1 问题 被一个行间距调疯了&#xff0c;就是样式改了没用&#xff0c;格式刷刷了没用。就是肉眼可以看出行间距完全不一样。 2 解决方法 1&#xff09;修改论文正文(即出现问题文本的样式)样式&#xff1a;样式>修改>格式>段落>缩进和间距>取消"如果定义了…

CDP集群安全指南-静态数据加密

[一]静态数据加密的架构 CDP 支持两种加密组件&#xff0c;这些组件可以组合成独特的解决方案。在选择密钥管理系统&#xff08;KMS&#xff09;时&#xff0c;您需要决定哪些组件能够满足企业的密钥管理和加密需求。 CDP 加密组件 以下是 Cloudera 用于静态数据加密的组件描…

ACM算法模板

ACM算法模板 起手式基础算法前缀和与差分二分查找三分查找求极值分治法&#xff1a;归并排序 动态规划基本线性 d p dp dp最长上升子序列I O ( n 2 ) O(n ^ 2) O(n2)最长上升子序列II O ( n l o g n ) O(nlogn) O(nlogn) 贪心二分最长公共子序列 背包背包求组合种类背包求排列…