【ONE·基础算法 || 队列(宽搜运用) 优先级队列(堆运用) 】

在这里插入图片描述

总言

  主要内容:编程题举例,熟悉理解宽搜类题型,队列、堆此类STL容器使用。
  
  

文章目录

  • 总言
  • 1、 宽搜
  • 2、N 叉树的层序遍历(medium)
    • 2.1、题解
  • 3、二叉树的锯齿形层序遍历(medium)
    • 3.1、题解
  • 4、二叉树的最大宽度(medium)
    • 4.1、题解
  • 5、在每个树行中找最大值(medium)
    • 5.1、题解
  • 6、优先级队列
  • 7、最后一块石头的重量(easy)
    • 7.1、题解
  • 8、数据流中的第 K 大元素(easy)
    • 8.1、题解
  • 9、前 K 个高频单词 (medium)
    • 9.1、题解
  • 10、数据流的中位数(hard)
    • 10.1、题解
  • Fin、共勉。

  
  
  
  

1、 宽搜

  搜索类算法有:深搜、宽搜。深搜我们在之前的博文中举例过很多例题。(递归&&二叉树深搜、回溯和剪枝(暴搜/深搜))
  这里,我们主要举例几道题目熟悉宽搜,由于宽搜是借助队列完成,因此此处例题也是对队列相关数据结构和容器的熟悉使用。其应用延伸会在floodfill和记忆化搜索中举例。
  
  相关复习博文:数据结构:栈&&队列、STL:stack&&queue
  
  
  

2、N 叉树的层序遍历(medium)

  题源:链接。

在这里插入图片描述

  

2.1、题解

  1)、思路分析
  说明: 我们曾写过二叉树的层序遍历(相关连接),这里原理相同,BFS需要借助栈来完成,无非是把二叉树改为了多叉树。

  注意细节: 在使用BFS遍历时,我们只是一股脑地将结果以层序遍历的方式打印出来。但这里的返回值为vector<vector<int>>,要求我们分层处理。
在这里插入图片描述

  如何控制BFS,每次只获取每层的结果? 我们可以使用一个变量levelsize来统计一层的结点数。那么每次出队列时,只需出这levelsize个结点即可。(PS:这里具体写法形式不固定,只要按照解题思路写出来即可,细节控制看自己。)
  
  
  2)、题解
  这种写法是在while总循环前就先统计一层的结点数量,每当出完 levelsize 个结点,就代表完成一层的遍历。此时队列剩余的元素即下一层的结点数目。

class Solution {
public:
    vector<vector<int>> levelOrder(Node* root) {
        vector<vector<int>> ret;// 用于返回最终结果(所有层)
        vector<int> level;// 用于统计每一层
        if(root == nullptr) return ret;// 题目结点存在空的情况

        std::queue<Node*> q;// 队列:用于层序遍历
        if(root)
            q.push(root);
        int levelsize = q.size();// 用于统计每一层的节点个数


        while(!q.empty())
        {
            Node* front = q.front();// 取队头元素
            q.pop();// 删除队头元素
            for(auto node : front->children)// 让当前结点的孩子⼊队
            {
                if(node != nullptr)
                    q.push(node);
            }

            level.push_back(front->val);//将当前取出的结点放入当前层统计中

            if(--levelsize <= 0)// 每放一次,就减一次当前层的结点数目,如果减到零,说明当前层已经出完,合计一次。
            {   
                ret.push_back(level);
                level.clear();// 清空
                levelsize = q.size();// 此时队列中存在的元素数目,就是下一层结点的总个数
            }
        }
        return ret;
    }
};

  这种写法是在每一层遍历开始前,先记录队列中的结点数量 levelsize(也就是这一层的结点数量),然后通过 for 循环,一次只处理 levelsize 个结点(也就是一次只出一层的结点数量)。

class Solution {
public:
    vector<vector<int>> levelOrder(Node* root) {
        vector<vector<int>> ret;// 用于返回最终结果(所有层)
        
        if(root == nullptr) return ret;// 题目结点存在空的情况

        std::queue<Node*> q;// 队列:用于层序遍历
        if(root)
            q.push(root);

        while(q.size())// 队列不为空时
        {
            int levelsize = q.size();// 统计当前队列中的元素个数(即当前层的总个数)
            vector<int> level;// 用于统计每一层
            for(int i = 0; i < levelsize; ++i)// 只需要出队levelsize次,即可出完当前层的所有元素,此时队列剩余的元素即下一层的结点数目
            {
                Node* front = q.front();// 取数
                q.pop();//删数
                level.push_back(front->val);
                for(auto node : front->children)
                {
                    q.push(node);
                }
            }
            ret.push_back(level);// 将一层数据计入最终返回结果中
        }
        return ret;
    }
};

  
  
  
  
  
  
  
  

3、二叉树的锯齿形层序遍历(medium)

  题源:链接。

在这里插入图片描述

  

3.1、题解

  1)、思路分析
  整体BFS思路不变,只是在适当的层需要进行逆序。因此,可额外增加一个标记位,让偶数层获取到的集合元素逆序即可。
在这里插入图片描述

  
  2)、题解
  标记位使用bool类型变量的方法:

class Solution {
public:
    vector<vector<int>> zigzagLevelOrder(TreeNode* root) {
        vector<vector<int>> ret;// 用于记录最终所有层的结果
        if(root == nullptr) return ret;

        std::queue<TreeNode*> q;// 用于进行层序遍历的队列
        bool flag = false;// 标记位:主要用来进行锯齿操作(false时:从左往右;true时,从右往左)
        q.push(root);
        while(!q.empty())// 队列不为空
        {
            int levelsize = q.size();// 统计当前层有多少结点
            vector<int> level;// 用于记录一层的遍历结果
            for(int i = 0; i < levelsize; ++i)// 根据统计结果,将当前层的结点出队
            {
                TreeNode* front = q.front();// 取队头
                q.pop();// 出队
                level.push_back(front->val);// 记录
                if(front->left) q.push(front->left);// 左孩子不为空,入队
                if(front->right) q.push(front->right);// 右孩子不为空,入队

            }
            if(flag)// 若flag为true,则逆序一次(相当于从右到左)
                reverse(level.begin(),level.end());

            ret.push_back(level);//将当前层计入最终统计结果中
            flag = !flag;// 修改标记位,以便下一层操作
        }
        return ret;
    }
};

  标记位使用int变量记录层数的方法:

class Solution {
public:
    vector<vector<int>> zigzagLevelOrder(TreeNode* root) {
        vector<vector<int>> ret;// 用于记录最终所有层的结果
        if(root == nullptr) return ret;

        std::queue<TreeNode*> q;// 用于进行层序遍历的队列
        int curlevel = 1;// 标记位:主要用来进行锯齿操作(这里记录的是层数)
        q.push(root);
        while(!q.empty())// 队列不为空
        {
            int levelsize = q.size();// 统计当前层有多少结点
            vector<int> level;// 用于记录一层的遍历结果
            for(int i = 0; i < levelsize; ++i)// 根据统计结果,将当前层的结点出队
            {
                TreeNode* front = q.front();// 取队头
                q.pop();// 出队
                level.push_back(front->val);// 记录
                if(front->left) q.push(front->left);// 左孩子不为空,入队
                if(front->right) q.push(front->right);// 右孩子不为空,入队

            }
            if(curlevel % 2 == 0)// 能被2除尽,说明是偶数层,需要从右往左
                reverse(level.begin(),level.end());

            ret.push_back(level);//将当前层计入最终统计结果中
            ++curlevel;// 进入下一层
        }
        return ret;
    }
};

  
  
  
  
  
  
  

4、二叉树的最大宽度(medium)

  题源:链接。

在这里插入图片描述

  

4.1、题解

  1)、思路分析
  思路一: 层层遍历,统计队列宽度(会超过内存限制)。
  利用层序遍历,把当前层的结点全部存在队列里面,利用队列的长度来计算每一层的宽度,统计出最大的宽度。需要注意,这里空节点也是需要计算在在队列内的。
  超时说明: 树中节点的数目范围是 [1, 3000],极端情况下,设只有最左边和最右边的长链,此时我们需要存几亿个空节点,会超过最⼤内存限制。
在这里插入图片描述

  
  
  
  思路二: 利用二叉树的顺序存储。通过根节点的下标,计算左右孩子的下标。
在这里插入图片描述

  
  
  2)、题解

class Solution {
public:
    int widthOfBinaryTree(TreeNode* root) {
        if(root == nullptr) return 0;
        vector<pair<TreeNode*,unsigned int>> q;// 用数组模拟队列
        unsigned int  maxwidth = 0;// 用于记录最宽的长度
        q.push_back({root,1});// 入队:这里将根结点编号设置为1
        while(!q.empty())// 不为空时
        {
            // 取当前层的首元素和尾元素,获取宽度差
            auto& [x1,y1] = q.front();
            auto& [x2,y2] = q.back();
            maxwidth = max(maxwidth, y2 - y1 + 1);// 这里y1、y2是对应结点的编号。
            // 入队下一层
            vector<pair<TreeNode*,unsigned int>> next;// 这里我们选择重新建立一个队列进行替换,如此可以省去出队时vector的头删(需要挪动数据)
            for(auto& [x,y] : q)
            {
                if(x->left) next.push_back({x->left, y*2});// 若左结点存在,将左结点入队
                if(x->right) next.push_back({x->right,y*2+1});// 若右结点存在,将右结点入队
            }
            q = next;// 替换
        }
        return maxwidth;
    }
};

  
  
  
  
  
  
  

5、在每个树行中找最大值(medium)

  题源:链接。

在这里插入图片描述

  

5.1、题解

  1)、思路分析
  说明: 可以在BFS层序遍历过程中,统计出每⼀层结点的最大值。

  2)、题解

class Solution {
public:
    vector<int> largestValues(TreeNode* root) {
        vector<int> ret;
        if(root == nullptr) return ret;

        std::queue<TreeNode*> q;// 用于层序遍历的队列
        q.push(root);// 将根结点入队
        while(!q.empty())
        {
            int maxinlevel = INT_MIN;// 用于记录当前层的最大值
            int sizelevel = q.size();// 当前层的元素个数
            for(int i = 0; i < sizelevel; ++i)
            {
                TreeNode* front = q.front();
                q.pop();
                maxinlevel = max(maxinlevel,front->val);

                if(front->left) q.push(front->left);
                if(front->right) q.push(front->right);
            }
            ret.push_back(maxinlevel);//一层遍历完,将当前层的最大值存入最终结果汇总
        }
        return ret;
    }
};

  
  
  
  
  
  
  
  
  

6、优先级队列

  前情回顾(方便复习):
  数组堆:相关博文链接
  priority_queue容器使用:相关博文链接
  
  
  
  
  

7、最后一块石头的重量(easy)

  题源:链接。

在这里插入图片描述

  
  

7.1、题解

  1)、思路分析
  说明:此题其实就是一个模拟的过程。可建立一个大堆,每次从石堆中拿出最大及次大的元素,将二者粉碎(做相关运算);如果运算结果还有剩余,就将剩余的结果存入原始的堆中。一直重复上述操作,直到堆中只剩下⼀个元素,或没有元素。
  
  2)、题解

class Solution {
public:
    int lastStoneWeight(vector<int>& stones) {
        priority_queue<int> heap;//创建一个大堆,将数据放入堆中
        for(auto e: stones)
            heap.push(e);

        while( heap.size() > 1)// 堆中存在两个及其以上的元素时,才取石头
        {
            int y = heap.top();heap.pop();// 大堆,取当前最大值。
            int x = heap.top();heap.pop();// 取次大值。

            int tmp = y - x;// 进行粉碎
            if(tmp) heap.push(tmp);// 若 x != y,将结果存入堆中
        }

        if(heap.size()) return heap.top();//若只剩下一块石头,返回此石头的重量。
        else return 0;//如果没有石头剩下,就返回 0。
    }
};

  
  
  
  
  
  

8、数据流中的第 K 大元素(easy)

  题源:链接。

在这里插入图片描述

  

8.1、题解

  1)、思路分析
  看到此题时,要想到它实际是TOP-K问题:从一个包含大量数据项的集合中找到前K个最重要(最大/最小)的元素。
  在学习数据结构堆时,我们讲过可以使用堆排序解决(相关链接)。时间复杂度为 O ( n l o g k ) O(nlogk) O(nlogk)
  在先前的并归专题我们也使用过快速选择排序解决(相关链接)。时间复杂度为 O ( n ) O(n) O(n)
  
  
  2)、题解
  这里我们主要以堆排解决该问题。要注意理解,排升序要用大根堆还是小根堆?为什么?(相关问题见链接部分的博文)

class KthLargest {
public:
    KthLargest(int k, vector<int>& nums) 
        :_k(k)
    { 
        int n = nums.size();
        
        // 建立一个小堆,放入k个元素。
        for(auto x : nums)
        {
            heap.push(x);
            if(heap.size() > _k) heap.pop();
        }
    }
    
    int add(int val) {

        heap.push(val);
        if(heap.size() > _k) heap.pop();

        return heap.top();
    }

    int _k;
    priority_queue<int,vector<int>,greater<int>> heap;
    // priority_queue默认大堆,用的是less;这里我们要创建小队,故类模板需要定义。
};

/**
 * Your KthLargest object will be instantiated and called as such:
 * KthLargest* obj = new KthLargest(k, nums);
 * int param_1 = obj->add(val);
 */

  
  
  
  
  
  
  

9、前 K 个高频单词 (medium)

  题源:链接。

在这里插入图片描述

  

9.1、题解

  1)、思路分析

  此题实际也是一个top-K 问题。要知道每⼀个单词出现的频次,因此可以先使用哈希表,统计出每一个单词出现的频次,然后在哈希表中,选出前 k 大的单词。(原数组中存在重复的单词,哈希表处理后无重复单词)
  统计完毕后,需要进行排序。 方法多种,这里主要讲解堆排(优先级队列的使用):排序需要满足两重条件。第一序列看单词频率,频率大的优先(基于频次比较的小根堆);第二序列看字典顺序,字母小的排在前面(基于字典序比较的大根堆)。
  定义好用于比较的容器后,依次将哈希表中的字符串插入到堆中,维持堆中的元素不超过 k 个;遍历完整个哈希表后,堆中的剩余元素就是前 k 大的元素。此时,需要将堆中元素提取返回。(这里取堆顶元素得到的是逆序,可以先将所有元素放入数组中来一次逆置,也可以直接倒着存入元素。)

  其它写法:map、set系列容器运用。
  
  2)、题解


class comple {
public:
    bool operator()(const pair<string, int>& x, const pair<string, int>& y) 
    {
        if(x.second == y.second)
            return x.first < y.frist;// 单词频率相同时,按照字典顺序比较(大根堆)
        return x.second > y.second;// 按照单词出现频率比较(这里建立的是小根堆)
    }
}

class Solution {
public:
    vector<string> topKFrequent(vector<string>& words, int k) {
        unordered_map<string, int>hash; // 定义一个哈希,用于统计单词及其出现频率
        for (auto& str : words) // 统计频率
            hash[str]++;

        // 使用堆排
        priority_queue<pair<string, int>, vector<pair<string, int>>, comple> heap;
        for(auto& pai : hash)
        {
            heap.push(pai);
            if(heap.size() > 0) heap.pop();
        }

        // 提取k个元素
        vector<string> ret(k);
        for(int i = k-1; i >= 0; --k)// 从后往前提取堆顶元素放入,可省去逆置
        {
            ret[i] = heap.top();
            heap.pop();
        }
        return ret;
    }
};

  
  
  
  
  
  
  
  

10、数据流的中位数(hard)

  题源:链接。

在这里插入图片描述

  
  

10.1、题解

  1)、思路分析
  思路一(超时): 使用vector容器存放序列,在每次查找中位数前进行快排,通过下标即可快速找到中位数。时间复杂度: a d d ( n l o g n ) add(nlogn) add(nlogn) f i n d ( 1 ) find(1) find(1)
  思路二(超时): 可以使用插入排序。时间复杂度: a d d ( n ) add(n) add(n) f i n d ( 1 ) find(1) find(1)
  
  
  思路三:利用大小堆维护数据流中的中位数。
  我们可以将整个数组按照大小平均分成两个序列,左序列和右序列(如果不能平分,那就让左侧较小的序列的元素多一个)。
  对左序列的元素,建立大根堆;对右序列的元素,建立小根堆。这样就能在 O ( 1 ) O(1) O(1) 的时间内拿到中间的一个数或者两个数,进而求得平均数。

在这里插入图片描述

  
  
  2)、题解
  

class MedianFinder {
    // 使用两个堆来维护数据流:[0,mid]建立大根堆,即包含中位数在内的左侧m个元素,[mid+1, n]建立小根堆,即中位数之后的n个元素。
    // 根据上述,由于数据存在偶数、奇数情况。这里我们默认将中位数放在大根堆中(即左区间中),则有m >= n (只会比n多一个元素)
    priority_queue<int> max_left;// 左区间:大根堆
    priority_queue<int, vector<int>,greater<int>> min_right;// 右区间:小根堆
public:
    MedianFinder() {

    }
    
    void addNum(int num) {
        int m = max_left.size(), n = min_right.size();// 获取当前两个堆中元素数目
        // 合法的情况:m == n、 m = n + 1。要保证放入元素num后,仍旧满足合法条件。
        if(m == n)// 放置元素num前,大根堆和小根堆元素相同
        {
            if(m == 0 || num <= max_left.top()) // 待加入元素需要放在左侧大根堆中,放入后 m = n + 1
            {
                max_left.push(num);
            }
            else{ // 待加入元素需要放在右侧小根堆中,放入后 m + 1 = n,因此需要挪动右侧堆顶元素入左侧(挪动后 m == n)
                min_right.push(num);
                max_left.push(min_right.top());
                min_right.pop();// 这里删除顺序不能乱。有可能放入的num恰好是右边小根堆的堆顶元素。
            }
        }
        else if(m == n + 1)// m > n
        {
            if(num <= max_left.top())// 待加入元素需要放在左侧大根堆中,放入后 m = n +2 ,因此则需要挪动左侧堆顶元素入右侧(挪动后:m == n)
            {
                max_left.push(num);// 将num元素放入左侧大根堆中:m = n + 2;
                min_right.push(max_left.top());// 将左侧大根堆中堆顶元素取出放入右侧小根堆中:m = n
                max_left.pop();
            }
            else// num > left
            {
                min_right.push(num);// 放入后,m = n
            }
        }
    }

    
    double findMedian() {
        int m = max_left.size(), n = min_right.size();// 获取当前两个堆中元素数目
        if(m == n)
        {
            return (max_left.top() + min_right.top()) / 2.0; // 注意整数除法和小数除法
        }
        else return max_left.top();
    }
};

  
  
  
  
  
  
  
  
  
  
  
  
  
  

Fin、共勉。

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【永洪BI】精确不同值计数

一、功能演示 二、使用说明 1、 功能简介 精确不同值计数&#xff0c;即统计所有数据行中不同数据值的总数量&#xff0c;数据值相同时只计算一次&#xff0c;如果存在维度字段&#xff0c;会按照不同类别分别计数。 2、 应用场景 想要统计数据中不同值出现的次数时可以使用…

Metasploit基本命令

1. 开启控制台 命令&#xff1a; msfconsole2. 搜索模块 命令&#xff1a; search ms17-010 # 模块名这里以搜索 ms17-010 为例&#xff0c; auxiliary 开头的为测试模块&#xff0c;也就是 POC&#xff0c;看看存不存在漏洞&#xff0c; exploit 开头的为攻击模块 3. 调…

DCMM(数据管理能力成熟度模型)对企业的价值

随着大数据时代的来临&#xff0c;数据已成为企业发展的重要驱动力。为了有效地管理和利用数据&#xff0c;企业需要建立一套完善的数据管理体系&#xff0c;而DCMM&#xff08;数据管理能力成熟度模型&#xff09;正是这样一个帮助企业构建和优化数据管理能力的框架。 DCMM结构…

芯片固定环氧胶有什么优点?

芯片固定环氧胶有什么优点&#xff1f; 芯片固定环氧胶在电子封装和芯片固定应用中具有多种显著优点&#xff0c;以下是其中的一些关键优势&#xff1a; 高粘接强度&#xff1a;环氧胶能够牢固地粘合芯片和基板&#xff0c;提供出色的粘接强度&#xff0c;确保芯片在各种环境条…

webpack优化构建速度示例-IgnorePlugin:

IgnorePlugin是webpack的一个内置插件&#xff0c;允许你忽略某些特定的模块或文件 webpack.config.jsconst config {entry: ./src/index.js,output: {filename: main.js},mode: development, }module.exports config;src/index.js import moment from moment console.log(mo…

剑指Offer打卡day34——AcWing 66. 两个链表的第一个公共结点

AcWing 66. 两个链表的第一个公共结点 暴力做法&#xff0c;两层for循环 /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode(int x) {* val x;* next null;* }* }*/ class Solutio…

LeetCode109:组合总和Ⅳ

题目描述 给你一个由 不同 整数组成的数组 nums &#xff0c;和一个目标整数 target 。请你从 nums 中找出并返回总和为 target 的元素组合的个数。 题目数据保证答案符合 32 位整数范围。 解题思想 使用完全背包 代码 /*dp[i]&#xff1a;表示装满容量为i的背包有dp[i]种方…

OpenHarmony上移植memtester

1. 下载源码&#xff1a; wget https://pyropus.ca./software/memtester/old-versions/memtester-4.6.0.tar.gz 2. 解压并指定交叉编译方式 解压 tar -xvf memtester-4.6.0.tar.gz 修改conf-cc和conf-ld&#xff0c;指定交叉编译方式 conf-cc conf-ld 3. 编译 直接运行m…

【问题实操】银河高级服务器操作系统实例分享,三台服务器宕机解决方式

1.服务器环境以及配置 物理机/虚拟机/云/容器 物理机 外网/私有网络/无网络 私有网络 处理器&#xff1a; Hygon C86 7265 24-core Processor 2 of 2 CPU sockets populated, 24 cores/48 threads per CPU 48 total cores, 96 total threads 内存&#xff1a; 768 GiB …

1W、2W 3KVAC隔离 宽电压输入 交直两用AC/DC 电源模块 ——TP01(02)AZ 系列

TP01(02)AZ为客户提供一款超小体积模块式开关电源&#xff0c;该系列模块电源输出功率为1W、2W&#xff0c;具有极低的空载损耗&#xff0c;低漏电流仅0.1mA&#xff0c;小体积&#xff0c;隔离耐压高达3KV等特点。产品安全可靠&#xff0c;EMC 性能好&#xff0c;EMC 及安全规…

哪个品牌的开放式耳机性价比高?五大高口碑优质爆款直入

最近几年来耳机音频市场上的质量问题层出不穷&#xff0c;就连最近火爆的开放式耳机也未能幸免。这是由于很多企业过分强调智能化、注重外形设计等&#xff0c;而忽视了作为一款开放式耳机最基本的音质和舒适性。很多品牌使用劣质材料制作开放式耳机产品&#xff0c;从而存在着…

英睿达硬盘数据恢复方法:从丢失到找回的详细指南

在数字化时代&#xff0c;硬盘作为我们存储重要数据的关键设备&#xff0c;承载着大量的个人、工作甚至商业信息。然而&#xff0c;无论是由于意外删除、格式化、病毒感染还是硬件故障&#xff0c;硬盘数据丢失的情况时有发生。英睿达硬盘作为市场上的知名品牌&#xff0c;其数…

基于yolov8+flask搭建一个web版本的网页模型预测系统

测试环境&#xff1a; anaconda3python3.8 torch1.9.0cu111 ultralytics8.2.2 首先我们将训练好的权重放在weights目录下面 并将名字改成yolov8n.pt&#xff0c;如果不想改可以在代码app.py都把路径改过来即可。然后我们打开 python app.py之后看到 我们点击选择文件支持图…

在PDF中使用Paragraph进行文本段落的处理

上一篇文章中我们使用itxtpdf库中的方法&#xff0c;绘制了一个固定表格与一个动态表格。如果你想在PDF中加入文字该怎么办呢。可以使用本文推荐的Paragraph这个类去实现&#xff0c;效果如下&#xff1a; 我在PDF中插入了一个工作流的审批流程。具体实现呢还是使用itextpdf库中…

0.98T优于10米高程DEM数据

我们在《全球30米100%水陆覆盖高程》一文中&#xff0c;为大家分享了全球100%覆盖&#xff0c;且包括海底高程的30米DEM数据。 该数据虽然全球无死角覆盖&#xff0c;但分辨率只有30米。 这里&#xff0c;再为大家分享一个优于10米的高程数据&#xff0c;但目前仅覆盖全国范围…

CSS学习笔记之中级教程(二)

CSS学习笔记之中级教程&#xff08;一&#xff09; 6、CSS 布局 - display: inline-block 与 display: inline 相比&#xff0c;主要区别在于 display: inline-block 允许在元素上设置宽度和高度。 同样&#xff0c;如果设置了 display: inline-block&#xff0c;将保留上下外…

Node.js基础:从入门到实战

初识 Node.js 与内置模块 &#xff08;初识&#xff09; 1、知道什么是node.js 2、知道node.js可以做什么 3、node.js 中js的组成部分 &#xff08;内置模块&#xff09; 4、用 fs 模块读写操作文件 5、使用 path 模块处理路径 6、使用http 模块写一个基本的web服务器 初识 N…

二.PVE创建 Ubuntu CT

二&#xff0e;PVE创建 Ubuntu CT 浏览器地址栏输入访问pve系统的网址&#xff0c;利用web端进行管理。注意进入pve系统时默认显示的有访问地址。本步骤的web访问地址为&#xff1a;https://192.168.1.102:8006。 出现该页面&#xff0c;选择继续前往。 进入管理页面后&…

图文成片剪辑软件,分享3个专业的工具!

在数字化时代&#xff0c;图文成片剪辑软件成为了我们创作与表达的重要工具。无论是想要制作一段引人入胜的短视频&#xff0c;还是打造一幅精美的图文海报&#xff0c;这些软件都能助你一臂之力。那么&#xff0c;图文成片剪辑软件的方法有哪些&#xff1f;又有哪些值得一试的…

衡量代理IP的因素

当你随便点开百度搜索IP代理&#xff0c;然后你就会看到&#xff0c;五花八门的IP代理商出现在视线中。再点进去链接&#xff0c;我们会发现&#xff0c;大多数IP代理商提供的基础IP服务都大差不差&#xff0c;东家这样说&#xff0c;西家又那样说&#xff0c;尽管我们看的头昏…