当前位置: 首页 > news >正文

如何理解二叉树与递归的关系

二叉树一般都是和递归有联系的,二叉树的遍历包括了前序,后序,中序,大部分题目只要考虑清楚应该用那种遍历顺序,然后特殊情况的条件,题目就会迎刃而解。

1. 先来说说二叉树的遍历方式

其实二叉树的遍历很简单,无论是前,后,中序都只需要记住三个步骤

  • 递归的参数和返回值
  • 递归终止条件
  • 递归单层逻辑

1. 1前序遍历(根左右)

// 不需要返回值,遍历当前树就可以
void preOrder(TreeNode* root) {if(root == nullptr) return;		// 终止条件// 单层逻辑cout << root->val;				// 根preOrder(root->left);			// 左preOrder(root->right);			// 右
}

1.2 后序遍历(左右根)

// 不需要返回值,遍历当前树就可以
void postOrder(TreeNode* root) {if(root == nullptr) return;		// 终止条件// 单层逻辑postOrder(root->left);			// 左cout << root->val;				// 根postOrder(root->right);			// 右
}

1.3 中序遍历(左根右)

// 不需要返回值,遍历当前树就可以
void postOrder(TreeNode* root) {if(root == nullptr) return;		// 终止条件// 单层逻辑postOrder(root->left);			// 左cout << root->val;				// 根postOrder(root->right);			// 右
}

2. 上题目

2.1 对称二叉树 Leetcode

  • 分析,什么是对称二叉树?左子树==右子树就是对称。
  • 返回值和参数。因为要比较左右两棵树,因此参数(TreeNode* left_tree, TreeNode* right_tree);这里需要比较左右子树,判断是否相等,因此返回值bool
bool isLeftEqualRight(TreeNode* left_tree, TreeNode* right_tree)
  • 终止条件。也是处理特殊情况
 if(left_tree == nullptr && right_tree == nullptr) return true;if(left_tree == nullptr && right_tree != nullptr) return false;if(left_tree != nullptr && right_tree == nullptr) return false;
  • 单层逻辑。想象成一个有三个节点(左中右)的二叉树,此时应该如何处理。在这里就要考虑遍历顺序的问题了。是先处理根节点还是后处理根节点。这里明显是先处理根节点。
if(left_tree->val != right_tree->val) return false;
bool b1 = dfs(left_tree->left, right_tree->right);
bool b2 = dfs(left_tree->right, right_tree->left);return b1 && b2;
  • 整体代码
bool isSymmetric(TreeNode* root) {if(root == nullptr) return true;return isLeftEqualRight(root->left, root->right);
}bool isLeftEqualRight(TreeNode* left_tree, TreeNode* right_tree) {// 终止条件if(left_tree == nullptr && right_tree == nullptr) return true;if(left_tree == nullptr && right_tree != nullptr) return false;if(left_tree != nullptr && right_tree == nullptr) return false;// 单层逻辑if(left_tree->val != right_tree->val) return false;bool b1 = dfs(left_tree->left, right_tree->right);bool b2 = dfs(left_tree->right, right_tree->left);return b1 && b2;
}

2.2 另一棵树的子树 Leetcode

  • 分析。子树如果在另一棵树出现过,说明另一棵树存在一棵树完全和子树相同,我们就只需要看是否有完全相同的树就可以
  • 返回值和参数。求是否包含,需要由左右子树的状态共同决定,返回值bool。求子树是否在另一棵树出现过,两个参数(TreeNode* root, TreeNode* subTree)
  • 终止条件。特殊情况
if(root == nullptr) return false;
  • 单层逻辑。当前树是否和子树完全相同,如果相同,返回true;否则看左右子树的情况
if(isSameTree(root, subRoot)) return true;//看左右子树,是否相等
return isSubtree(root->left, subRoot) || isSubtree(root->right, subRoot);

这里需要求两棵树是否完全一样isSameTree(TreeNode* p, TreeNode* q)

bool isSameTree(TreeNode* p, TreeNode* q) {if(p == nullptr && q == nullptr) return true;if(p == nullptr && q != nullptr) return false;if(p != nullptr && q == nullptr) return false;if(p->val != q->val) return false;bool b1 = isSameTree(p->left, q->left);bool b2 = isSameTree(p->right, q->right);return b1 && b2;
}
  • 完整代码
//subRoot是root的子树,root中一定有一个树结构和subRoot相等
bool isSubtree(TreeNode* root, TreeNode* subRoot) 
{//终止条件if(root == nullptr) return false;if(isSameTree(root, subRoot)) return true;//看左右子树,是否相等return isSubtree(root->left, subRoot) || isSubtree(root->right, subRoot);
}bool isSameTree(TreeNode* p, TreeNode* q)
{if(p == nullptr && q == nullptr) return true;else if(p == nullptr && q != nullptr) return false;else if(p != nullptr && q == nullptr) return false;else if(p->val != q->val) return false;return isSameTree(p->left, q->left) && isSameTree(p->right, q->right);
}

2.3 二叉树的最大深度 Leetcode

  • 分析,二叉树的最大深度?max(左子树深度, 右子树深度) + 1
  • 返回值和参数。求当前树,只需要当前树就可以,参数(TreeNode* root);求深度,返回值int
int maxDepth(TreeNode* root)
  • 终止条件。特殊条件
if(root == nullptr) return 0;
  • 单层逻辑。确定遍历顺序。因为当前树的情况依赖与左右子树的情况,因此需要先遍历左右,再处理根节点,显然后续。
int left_depth = maxDepth(root->left);
int right_depth = maxDepth(root->right);return max(left_depth, right_depth) + 1;
  • 完整代码
int maxDepth(TreeNode* root) {// 终止条件if(root == nullptr) return 0;// 单层逻辑int left_depth = maxDepth(root->left);int right_depth = maxDepth(root->right);return max(left_depth, right_depth) + 1;}

2.4 二叉树的最小深度 Leetcode

  • 分析,最小深度?左右子树深度的最小值确定当前当前树的最小深度。但是如果左子树为空,那最小深度一定由右子树确定。反之类似。
  • 返回值和参数。求当前树,只需要当前树就可以,参数(TreeNode* root);求深度,返回值int
  • 终止条件。特殊情况
if(root == nullptr) return 0;
  • 单层逻辑。想象有三个节点(左中右)的树,当前树的最小深度由左右子树共同确定,因此是后序遍历。这里需要注意,如果左子树为空,那最小深度就是右子树。反之类似。
int left_depth = minDepth(root->left);
int right_depth = minDepth(root->right);// 左子树为nullptr,由右子树确定
if(root->left == nullptr) return right_depth + 1;
if(root->right == nullptr) return left_depth + 1;return min(left_depth, right_depth) + 1;
  • 完整代码
int minDepth(TreeNode* root) {// 终止条件if(root == nullptr) return 0;// 单层逻辑int left_depth = minDepth(root->left);int right_depth = minDepth(root->right);if(root->left == nullptr) return right_depth + 1;if(root->right == nullptr) return left_depth + 1;return min(left_depth, right_depth) + 1;
}

2.5 平衡二叉树 Leetcode

  • 分析。什么是平衡二叉树?左子树高度-右子树高度 <= 1,因此我们要求左右子树的高度,然后比较两者差值
  • 返回值和参数。求当前树,只需要当前树就可以,参数(TreeNode* root);求高度,返回值int
  • 终止条件。特殊情况
if(root == nullptr) return 0;
  • 单层逻辑。判断左右子树的高度差,>1,返回-1表示不是平衡的,当正常返回高度,就是平衡的。这里其实设计到剪枝操作,每次不满足条件了,我们应该提前返回。
int left_height = getHeight(root->left);
if(left_height == -1) return -1;
int right_height = getHeight(root->right);
if(right_height == -1) return -1;if(abs(left_height-right_height) > 1) return -1;
else return max(left_height, right_height) + 1;
  • 完整代码
bool isBalanced(TreeNode* root) {return getHeight(root) == -1 ? false : true;}// 左右高度差 <= 1
int getHeight(TreeNode* root) {if(root == nullptr) return 0;int left_height = getHeight(root->left);if(left_height == -1) return -1;int right_height = getHeight(root->right);if(right_height == -1) return -1;if(abs(left_height-right_height) > 1) return -1;else return max(left_height, right_height) + 1;
}

2.6 完全二叉树的节点个数 Leetcode

  • 分析。完全二叉树是由满二叉树构成,如果当前是满二叉树(左右子树高度一样),那直接就(2 << n) - 1,然后再计算左右子树的节点数量,最后确定当前树的节点数量
  • 返回值和参数。求当前树,只需要当前树就可以,参数(TreeNode* root);求节点个数,返回值int
int countNodes(TreeNode* root)
  • 终止条件。特殊情况
if(root == nullptr) return 0;
  • 单层逻辑。当前是树是满二叉树(左右子树高度一样),直接算(2 << n) - 1。否则求左右子树节点数量。
TreeNode* left_tree = root->left;
TreeNode* right_tree = root->right;
int left_height = 0;
int right_height = 0;while(left_tree) {left_height++;left_tree = left_tree->left;
}while(right_tree) {right_height++;right_tree = right_tree->right;
}if(left_height == right_height) {return (2<<left_height) - 1;
}int c1 = countNodes(root->left);
int c2 = countNodes(root->right);return c1 + c2 + 1;
  • 完整代码
 int countNodes(TreeNode* root) {if(root == nullptr) return 0;// 当前是不是满二叉树(左子树高度和右子树高度一样)TreeNode* left_tree = root->left;TreeNode* right_tree = root->right;int left_height = 0;int right_height = 0;while(left_tree){left_height++;left_tree = left_tree->left;}while(right_tree){right_height++;right_tree = right_tree->right;}if(left_height == right_height){return (2<<left_height) - 1;}int c1 = countNodes(root->left);int c2 = countNodes(root->right);return c1 + c2 + 1;
}

2.7 二叉树的所有路径 Leetcode

  • 分析。路径:每次从根节点遍历到叶子节点root->left == nullptr && root->right == nullptr时,就是一条完整的路径,应该记录来。
  • 返回值与参数。因为每次递归涉及到当前节点和路径,因此参数(TreeNode* root, string path)。这里我们虽然要求所有的路径,但是这是整棵树情况,相当于是遍历整棵树,并不需要左右子树的结果才能推出当前树的结果(平衡,最大最小深度,节点个数都需要左右子树的状态才能确定当前树的状态),所以返回值void。这里需要注意,我们需要一个全局遍历,存最后的结果vector<string> res
  • 终止条件。特殊情况
if(root == nullptr) return;
  • 单层逻辑。当遍历到当前节点并且满足是叶子节点时,说明path记录了完整路径,需要被记录。否则就需要继续处理左右子树。
if(root == nullptr) return;// 每次进来先把当前节点的值加入到路径
path += to_string(root->val);if(root->left == nullptr && root->right == nullptr)
{res.push_back(path);
}//这里已经回溯过了
dfs(root->left, path + "->");
dfs(root->right, path + "->");
  • 完整代码
vector<string> res;vector<string> binaryTreePaths(TreeNode* root) 
{if(root == nullptr) return res;string path = "";dfs(root,  path);return res;
}void dfs(TreeNode* root, string path)
{if(root == nullptr) return;path += to_string(root->val);if(root->left == nullptr && root->right == nullptr){res.push_back(path);}//这里已经回溯过了dfs(root->left, path + "->");dfs(root->right, path + "->");
}

2.8 路径总和 Leetcode

  • 分析。路径:每次从根节点遍历到叶子节点root->left == nullptr && root->right == nullptr时,就是一条完整的路径,此时需要看targetNum是否刚好==0,刚好等于0说明这条路径上的和就是targetNum
  • 返回值和参数。是否满足条件,并且当前树的情况和左右子树的状态都有关系,返回值bool。参数,当前树,有无满足路径和为targetNum的,因此需要两个参数(TreeNode* root, int targetNum)
  • 终止条件。特殊情况
if(root == nullptr) return false;
  • 单层逻辑。如果当前节点是叶子节点,说明已经找到一条路径,判断targetNum是否是0,是就返回true;否则还需要看左右子树的状态
// 先记录当前值
targetSum -= root->val;
if(root->left == nullptr && root->right == nullptr)
{if(targetSum == 0){return true;}
}bool b1 = hasPathSum(root->left, targetSum);
if(b1) return true;bool b2 = hasPathSum(root->right, targetSum);        
if(b2) return true;return false;
  • 完整代码
bool hasPathSum(TreeNode* root, int targetSum) {
if(root == nullptr) return false;targetSum -= root->val;
if(root->left == nullptr && root->right == nullptr)
{if(targetSum == 0){return true;}
}bool b1 = hasPathSum(root->left, targetSum);
if(b1) return true;	// 一个剪枝操作bool b2 = hasPathSum(root->right, targetSum);        
if(b2) return true;return false;
}

2.9 左叶子之和 Leetcode

  • 分析。什么是左叶子?root->left && root->left->left == nullptr && root->left->right == nullptr说明root->left就是左叶子
  • 返回值和参数。求做左叶子之和,当前节点依赖于左右子树的状态,返回值int。求当前树,参数(TreeNode* root)
  • 终止条件。特殊情况
if(root == nullptr) return 0;
  • 单层逻辑。找当前节点的左叶子,然后再找左右子树的做叶子之和。
// 当前节点的左叶子节点
int curValue = 0;
if(root->left && root->left->left == nullptr && root->left->right == nullptr) 
{   curValue = root->left->val;
}int s1 = sumOfLeftLeaves(root->left);
int s2 = sumOfLeftLeaves(root->right);return s1 + s2 + curValue;
  • 完整代码
int sumOfLeftLeaves(TreeNode* root) {if(root == nullptr) return 0;
// 当前节点的左叶子节点
int curValue = 0;
if(root->left && root->left->left == nullptr && root->left->right == nullptr) 
{   curValue = root->left->val;
}int s1 = sumOfLeftLeaves(root->left);
int s2 = sumOfLeftLeaves(root->right);return s1 + s2 + curValue;}

2.10 找树左下角的值 Leetcode

  • 分析。左下角的值?最深的一层的第一个节点。因此需要一个变量记录树当前的最大深度max_depth
  • 返回值与参数。找最左下角的值,但是当前树最左下的值和左右子树的状态没有关系,返回值void。要判断当前节点的深度是不是最大深度,因此有两个参数(TreeNode* root, int depth)
  • 终止条件。特殊情况
if(root == nullptr) return;
  • 单层逻辑。遍历到叶子节点时,如果该叶子节点所在深度大于max_depth,说明该叶子节点是当前层的第一个节点(左叶子节点)。没找到,就继续在左右子树找
if(root->left == nullptr && root->right == nullptr)
{if(depth > max_depth) {res = root->val;max_depth = depth;}
}dfs(root->left, depth+1);
dfs(root->right, depth+1);
  • 完整代码
int max_depth = INT_MIN;
int res = 0;
int findBottomLeftValue(TreeNode* root) {if(root == nullptr) return 0;dfs(root, 1);return res;
}void dfs(TreeNode* root, int depth)
{if(root == nullptr) return;if(root->left == nullptr && root->right == nullptr){if(depth > max_depth) {res = root->val;max_depth = depth;}}dfs(root->left, depth+1);dfs(root->right, depth+1);
}

3. 二叉树的修改与构造

3.1 翻转二叉树 Leetcode

  • 分析。要想翻转一棵二叉树,先翻转左右子树,先翻转当前节点左右子树,明显是后序
  • 返回值和参数。要求翻转后的二叉树,并且当前树的状态和左右子树有关系,因此返回值TreeNode*。求当前树,参数(TreeNode* root)
  • 终止条件。特殊情况
if(root == nullptr) return nullptr;
  • 单层逻辑。先翻转左右子树,先翻转当前节点左右子树。
TreeNode* left_tree = invertTree(root->left);
TreeNode* right_tree = invertTree(root->right);root->left = right_tree;
root->right = left_tree;return root;
  • 完整代码
TreeNode* invertTree(TreeNode* root) {
if(root == nullptr) return nullptr;TreeNode* left_tree = invertTree(root->left);
TreeNode* right_tree = invertTree(root->right);root->left = right_tree;
root->right = left_tree;return root;
}

3.2 从中序与后序遍历序列构造二叉树 Leetcode

  • 分析。后序:左右中;中序:左中右。我们可以在后序中找到中间节点(最后一个),然后再根据该节点划分中序,分成左,中,右三个部分,然后就可以递归处理左,右。
  • 返回值和参数。要求构造的二叉树,当前树和左右子树的状态有关系,返回值TreeNode*。我们每次要确定中序和后序的左右边界,一个好的想法是直接在参数中表明,因此参数(vector<int>& inorder, int inStart, int inEnd, vector<int>& postorder, int postStart, int postEnd)
  • 终止条件。特殊情况
if(inStart >= inEnd) return nullptr;
  • 单层逻辑。先在后序找到中节点,再根据中节点将中序划分为左,中,右,最后递归处理左,右子树
//在前序找中
int mid_val = postorder[postEnd - 1];
TreeNode* root = new TreeNode(mid_val);//在中序找中
int mid_idx = 0;
for(int i = inStart; i<inEnd; ++i)
{if(inorder[i] == mid_val){mid_idx = i;break;}
}//左子树
int inLeftStart = inStart;
int inLeftEnd = mid_idx;
int postLeftStart = postStart;
int postLeftEnd = postStart + mid_idx - inStart;
TreeNode* left_tree = dfs(inorder, inLeftStart, inLeftEnd, postorder, postLeftStart, postLeftEnd);//右子树
int inRightStart = inLeftEnd + 1;
int inRightEnd = inEnd;
int postRightStart = postLeftEnd;
int postRightEnd = postEnd - 1;
TreeNode* right_tree = dfs(inorder, inRightStart, inRightEnd, postorder, postRightStart, postRightEnd);root->left = left_tree;
root->right = right_tree;return root;
  • 完整代码
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {return dfs(inorder, 0, inorder.size(), postorder, 0, postorder.size());
}TreeNode* dfs(vector<int>& inorder, int inStart, int inEnd, vector<int>& postorder, int postStart, int postEnd)
{if(inStart >= inEnd) return nullptr;//在前序找中int mid_val = postorder[postEnd - 1];TreeNode* root = new TreeNode(mid_val);//在中序找中int mid_idx = 0;for(int i = inStart; i<inEnd; ++i){if(inorder[i] == mid_val){mid_idx = i;break;}}//左子树int inLeftStart = inStart;int inLeftEnd = mid_idx;int postLeftStart = postStart;int postLeftEnd = postStart + mid_idx - inStart;TreeNode* left_tree = dfs(inorder, inLeftStart, inLeftEnd, postorder, postLeftStart, postLeftEnd);//右子树int inRightStart = inLeftEnd + 1;int inRightEnd = inEnd;int postRightStart = postLeftEnd;int postRightEnd = postEnd - 1;TreeNode* right_tree = dfs(inorder, inRightStart, inRightEnd, postorder, postRightStart, postRightEnd);root->left = left_tree;root->right = right_tree;return root;
}

3.3 最大二叉树 Leetcode

  • 分析。先找到最大值,再划分左右子树,递归处理左右子树
  • 返回值和参数。求构造的最大二叉树,并且当前树依赖于左右节点状态,返回值TreeNode*。确定当前处理的区间,参数·(vector<int>& nums, int start, int end)
  • 终止条件。特殊情况
if(start >= end) return nullptr;
  • 单层逻辑。先找到最大值,再划分左右子树,递归处理左右子树
//找到最大值
int max_val = INT_MIN;
int max_idx = -1;
for(int i = start; i<end; ++i)
{if(nums[i] > max_val){max_val = nums[i];max_idx = i;}
}TreeNode* root = new TreeNode(max_val);//左
int leftStart = start;
int leftEnd = max_idx;
TreeNode* left_tree = dfs(nums, leftStart, leftEnd);
//右
int rightStart = leftEnd + 1;
int rightEnd = end;
TreeNode* right_tree = dfs(nums, rightStart, rightEnd);root->left = left_tree;
root->right = right_tree;return root;        

3.4 合并二叉树 Leetcode

  • 分析。如果两棵树都不是null,把root2合并到root1上。先处理当前节点,然后处理左右子树。
  • 返回值和参数。求合并后的二叉树,并且当前树和左右子树的状态有关系,因此返回值TreeNode*。合并两个数,参数(TreeNode* root1, TreeNode* root2)
  • 终止条件。当任意一棵树为null,返回另一棵树
if(root1 == nullptr) return root2;
if(root2 == nullptr) return root1;
  • 单层逻辑。如果两棵树都不是null,把root2合并到root1上。先处理当前节点,然后处理左右子树。
root1->val = root1->val + root2->val;TreeNode* left_tree = mergeTrees(root1->left, root2->left);
TreeNode* right_tree = mergeTrees(root1->right, root2->right);root1->left = left_tree;
root1->right = right_tree;return root1;
  • 完整代码
TreeNode* mergeTrees(TreeNode* root1, TreeNode* root2) {if(root1 == nullptr) return root2;if(root2 == nullptr) return root1;root1->val = root1->val + root2->val;TreeNode* left_tree = mergeTrees(root1->left, root2->left);TreeNode* right_tree = mergeTrees(root1->right, root2->right);root1->left = left_tree;root1->right = right_tree;return root1;
}

相关文章:

如何理解二叉树与递归的关系

二叉树一般都是和递归有联系的&#xff0c;二叉树的遍历包括了前序&#xff0c;后序&#xff0c;中序&#xff0c;大部分题目只要考虑清楚应该用那种遍历顺序&#xff0c;然后特殊情况的条件&#xff0c;题目就会迎刃而解。 1. 先来说说二叉树的遍历方式 其实二叉树的遍历很简…...

CSS 高级技巧

目录 1.精灵图 1.1为什么需要精灵图 1.2 精灵图&#xff08;sprites&#xff09;的使用 2.字体图标 2.1字体图标的产生 2.2字体图标的优点 2.3字体图标的下载 2.4字体图标的引入 2.5字体图标的追加 1.精灵图 1.1为什么需要精灵图 一个网站往往回应用很多的小背景图像作…...

ToBeWritten之MIPS汇编基础铺垫

也许每个人出生的时候都以为这世界都是为他一个人而存在的&#xff0c;当他发现自己错的时候&#xff0c;他便开始长大 少走了弯路&#xff0c;也就错过了风景&#xff0c;无论如何&#xff0c;感谢经历 转移发布平台通知&#xff1a;将不再在CSDN博客发布新文章&#xff0c;敬…...

MySQL数据库对数据库表的创建和DML操作

1&#xff0e;创建表user&#xff0c;其中包含id、name、password,其中主键自增&#xff0c;name&#xff0c;唯一是可变长度&#xff0c;最大长度是30&#xff0c;密码&#xff0c;可变长度&#xff0c;最大长度为20&#xff0c;不为空。 以下是创建符合要求的user表的SQL语句…...

【PCB专题】PCB 阻焊层(solder mask)与助焊层(paste mask)有什么区别

一块标准的印刷电路板 (PCB) 通常需要两种不同类型的“罩层 (mask)”。其中阻焊层 (solder mask) 和助焊层 (paste mask) 都是“罩层”,但在 PCB 制造过程中,它们分别用于两个完全不同的部分,因此也存在很大的区别。 阻焊层定义 阻焊层定义了电路板外表面的保护材料涂抹范围…...

ThreeJS-纹理旋转、重复(十一)

旋转 文档&#xff1a;three.js docs 关键代码&#xff1a; //设置旋转中心,默认左下角 docColorLoader.center.set(0.5,0.5); //围绕旋转中心逆时针旋转45度 docColorLoader.rotation Math.PI/4; 完整代码: <template> <div id"three_div"></div>…...

CSDN——Markdown编辑器——官方指导

CSDN——Markdown编辑器——官方指导欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表…...

DN-DETR调试记录

博主在进行DINO实验过程中&#xff0c;发现在提取了3个类别的COCO数据集中&#xff0c;DINO-DETR对car,truck的检测性能并不理想&#xff0c;又通过实验自己的数据集&#xff0c;发现AP值相差不大且较为符合预期&#xff0c;因此便猜想是否是由于DINO中加入了负样本约束导致背景…...

ASP消防网上考试系统设计与实现

本文以ASP和Access数据库来开发服务器端&#xff0c;通过计算机网络技术实现了一个针对消防部队警官的网上考试系统。为了。提高消防部队的工作效率和信息化水平&#xff0c;体现消防部队信息化进程的特色&#xff0c;开发一个适合消防部队的计算机网上考试系统是非常必要的。鉴…...

MongoDB - 数据模型的设计模式

简介 官方文章的地址是 Building with Patterns: A Summary&#xff0c;其中汇总了 12 种设计模式及使用场景。 上述的图表列举了 12 种设计模式及应用场景&#xff0c;主要是以下这些&#xff1a; 近似值模式&#xff08;Approximation Pattern&#xff09;属性模式&#xf…...

3D格式转换工具助力Shapr3D公司产品实现了 “无障碍的用户体验”,可支持30多种格式转换!

今天主要介绍的是HOOPS Exchange——一款支持30多种CAD文件格式读取和写入的工具&#xff0c;为Shapr3D公司提供的重要帮助! Shapr3D是一家有着宏伟目标的公司&#xff1a;将CAD带入21世纪&#xff01;该公司于2016年首次推出其同名应用程序&#xff0c;并将Shapr3D带到了macOS…...

虚拟环境-----virtualenv和pipenv的安装和应用

1.pip install virtualenv 2.pip安装虚拟环境管理包virtualenvwrapper-win 3.创建一个存放虚拟环境的目录&#xff08;建议命名为.env或者.virtualenv&#xff09; 4.配置环境变量&#xff08;变量名&#xff1a;WORKON_HOME,值&#xff1a;上面创建的目录路径&#xff09; …...

awd pwn——LIEF学习

文章目录1. 什么是LIEF2. 加载可执行文件3. 修改ELF的symbols4. ELF Hooking5. 修改got表6. 总结1. 什么是LIEF LIEF是一个能够用于对各种类型的可执行文件&#xff08;包括Linux ELF文件、Windows exe文件、Android Dex文件等&#xff09;进行转换、提取、修改的项目&#xf…...

亚商投资顾问 早餐FM/0330 6G发展持开放态度

01/亚商投资顾问 早间导读 1.工信部副部长&#xff1a;中国对6G发展持开放的态度已成立工作组推动关键技术研究 2.易纲、周小川最新发声 中国加快绿色低碳发展的决心坚定不移 3.中移动出手&#xff01;450亿溢价包圆邮储银行定增股份 4.海南全面启动全岛封关运作准备 免税消…...

cookie和session的区别

文章目录cookie和session的区别1. 存储位置不同2. 生命周期不同3. 存储数据大小不同4. 数据类型不同5. 安全性不同cookie和session的区别 1. 存储位置不同 cookie&#xff1a;cookie数据保存在客户端。 session&#xff1a;session数据保存在服务器端。 2. 生命周期不同 s…...

android 人脸考勤机 卡死原因

Android人脸考勤机卡死的原因可能有以下几个方面&#xff1a; 硬件限制&#xff1a;如果使用的设备性能较低&#xff0c;如处理器、内存、存储等都不足以支持应用程序的运行&#xff0c;就容易出现卡顿、卡死等问题。 代码优化&#xff1a;代码的优化也是影响应用程序性能的重…...

安装k8s工具之三-kube-ansible

一、介绍 Kube-ansible 是一个开源的 Kubernetes 部署和管理工具&#xff0c;它使用 Ansible 自动化工具来管理 Kubernetes 集群。Kube-ansible 提供了一套可扩展的框架&#xff0c;可以方便地部署和管理 Kubernetes 集群。 Kube-ansible 的主要特点包括&#xff1a; 支持多…...

《程序员面试金典(第6版)》面试题 08.09. 括号(回溯算法,特殊的排列问题,C++)

题目描述 括号。设计一种算法&#xff0c;打印n对括号的所有合法的&#xff08;例如&#xff0c;开闭一一对应&#xff09;组合。 说明&#xff1a;解集不能包含重复的子集。 例如&#xff0c;给出 n 3&#xff0c;生成结果为&#xff1a; ["((()))","(()())…...

大厂面试篇--2023软件测试八股文最全文档,有它直接大杀四方

前言 已经到了金三银四的黄金招聘季节了&#xff0c;还在准备面试跳槽涨薪的小伙伴们可以看看本篇文章哟&#xff0c;这里呢笔者就不多说废话了直接上干货&#xff01;答案已整理好&#xff0c;文末拿去即可&#xff01;非常好用&#xff01; 一、字节跳动测试面经篇 1、在搜…...

LeetCode326_326. 3 的幂

LeetCode326_326. 3 的幂 一、描述 给定一个整数&#xff0c;写一个函数来判断它是否是 3 的幂次方。如果是&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 整数 n 是 3 的幂次方需满足&#xff1a;存在整数 x 使得 n 3的x次方 示例 1&#xff1a; 输…...

Java 语言特性(面试系列1)

一、面向对象编程 1. 封装&#xff08;Encapsulation&#xff09; 定义&#xff1a;将数据&#xff08;属性&#xff09;和操作数据的方法绑定在一起&#xff0c;通过访问控制符&#xff08;private、protected、public&#xff09;隐藏内部实现细节。示例&#xff1a; public …...

【WiFi帧结构】

文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成&#xff1a;MAC头部frame bodyFCS&#xff0c;其中MAC是固定格式的&#xff0c;frame body是可变长度。 MAC头部有frame control&#xff0c;duration&#xff0c;address1&#xff0c;address2&#xff0c;addre…...

渗透实战PortSwigger靶场-XSS Lab 14:大多数标签和属性被阻止

<script>标签被拦截 我们需要把全部可用的 tag 和 event 进行暴力破解 XSS cheat sheet&#xff1a; https://portswigger.net/web-security/cross-site-scripting/cheat-sheet 通过爆破发现body可以用 再把全部 events 放进去爆破 这些 event 全部可用 <body onres…...

UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)

UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中&#xff0c;UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化&#xf…...

【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统

目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索&#xff08;基于物理空间 广播范围&#xff09;2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...

JVM 内存结构 详解

内存结构 运行时数据区&#xff1a; Java虚拟机在运行Java程序过程中管理的内存区域。 程序计数器&#xff1a; ​ 线程私有&#xff0c;程序控制流的指示器&#xff0c;分支、循环、跳转、异常处理、线程恢复等基础功能都依赖这个计数器完成。 ​ 每个线程都有一个程序计数…...

Java毕业设计:WML信息查询与后端信息发布系统开发

JAVAWML信息查询与后端信息发布系统实现 一、系统概述 本系统基于Java和WML(无线标记语言)技术开发&#xff0c;实现了移动设备上的信息查询与后端信息发布功能。系统采用B/S架构&#xff0c;服务器端使用Java Servlet处理请求&#xff0c;数据库采用MySQL存储信息&#xff0…...

【Redis】笔记|第8节|大厂高并发缓存架构实战与优化

缓存架构 代码结构 代码详情 功能点&#xff1a; 多级缓存&#xff0c;先查本地缓存&#xff0c;再查Redis&#xff0c;最后才查数据库热点数据重建逻辑使用分布式锁&#xff0c;二次查询更新缓存采用读写锁提升性能采用Redis的发布订阅机制通知所有实例更新本地缓存适用读多…...

MinIO Docker 部署:仅开放一个端口

MinIO Docker 部署:仅开放一个端口 在实际的服务器部署中,出于安全和管理的考虑,我们可能只能开放一个端口。MinIO 是一个高性能的对象存储服务,支持 Docker 部署,但默认情况下它需要两个端口:一个是 API 端口(用于存储和访问数据),另一个是控制台端口(用于管理界面…...

【Elasticsearch】Elasticsearch 在大数据生态圈的地位 实践经验

Elasticsearch 在大数据生态圈的地位 & 实践经验 1.Elasticsearch 的优势1.1 Elasticsearch 解决的核心问题1.1.1 传统方案的短板1.1.2 Elasticsearch 的解决方案 1.2 与大数据组件的对比优势1.3 关键优势技术支撑1.4 Elasticsearch 的竞品1.4.1 全文搜索领域1.4.2 日志分析…...