【优选算法之队列+宽搜/优先级队列】No.14--- 经典队列+宽搜/优先级队列算法

news2024/10/4 13:59:46

文章目录

  • 前言
  • 一、队列+宽搜示例:
    • 1.1 N 叉树的层序遍历
    • 1.2 ⼆叉树的锯⻮形层序遍历
    • 1.3 ⼆叉树最⼤宽度
    • 1.4 在每个树⾏中找最⼤值
  • 二、优先级队列(堆)示例:
    • 2.1 最后⼀块⽯头的重量
    • 2.2 数据流中的第 K ⼤元素
    • 2.3 前 K 个⾼频单词
    • 2.4 数据流的中位数


前言

在这里插入图片描述

👧个人主页:@小沈YO.
😚小编介绍:欢迎来到我的乱七八糟小星球🌝
📋专栏:优选算法
🔑本章内容:队列+宽搜/优先级队列
记得 评论📝 +点赞👍 +收藏😽 +关注💞哦~


一、队列+宽搜示例:

1.1 N 叉树的层序遍历

  1. 题⽬链接:429. N 叉树的层序遍历
  2. 题⽬描述:
    在这里插入图片描述
  3. 解法:
    算法思路:
    层序遍历即可~
    仅需多加⼀个变量,⽤来记录每⼀层结点的个数就好了。
  4. C++代码
/*
// Definition for a Node.
class Node {
public:
    int val;
    vector<Node*> children;

    Node() {}

    Node(int _val) {
        val = _val;
    }

    Node(int _val, vector<Node*> _children) {
        val = _val;
        children = _children;
    }
};
*/

class Solution {
public:
    vector<vector<int>> levelOrder(Node* root) 
    {
        vector<vector<int>> vv;
        vector<int> v;
        if(root==nullptr)return vv;
        queue<Node*> q;
        q.push(root);
        while(!q.empty())
        {
            int sz=q.size();//统计本层节点个数
            while(sz--)
            {
                Node* tmp=q.front();
                v.push_back(tmp->val);
                q.pop();
                for(auto&e:tmp->children)//逐次加入孩子节点
                {
                    if(e!=nullptr)
                    q.push(e);
                }
            }
            vv.push_back(v);
            v.clear();
        }
        return vv;
    }
};

1.2 ⼆叉树的锯⻮形层序遍历

  1. 题⽬链接:103. ⼆叉树的锯⻮形层序遍历
  2. 题⽬描述:
    在这里插入图片描述
  3. 解法(层序遍历):
    算法思路:
    在正常的层序遍历过程中,我们是可以把⼀层的结点放在⼀个数组中去的。
    既然我们有这个数组,在合适的层数逆序就可以得到锯⻮形层序遍历的结果。
  4. C++代码
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    vector<vector<int>> zigzagLevelOrder(TreeNode* root) 
    {
        vector<vector<int>> vv;
        vector<int> v;
        if(root==nullptr)return vv;
        int cnt=0;
        queue<TreeNode*> q;
        q.push(root);
        while(!q.empty())
        {
            cnt++;
            int sz=q.size();
            while(sz--)
            {
                TreeNode* tmp=q.front();
                q.pop();
                v.push_back(tmp->val);
                if(tmp->left!=nullptr)q.push(tmp->left);
                if(tmp->right!=nullptr)q.push(tmp->right);
            }
            if(cnt%2==0)reverse(v.begin(),v.end());
            vv.push_back(v);
            v.clear();
        }
        return vv;
    }
};

1.3 ⼆叉树最⼤宽度

  1. 题⽬链接:662. ⼆叉树最⼤宽度
  2. 题⽬描述:
    在这里插入图片描述
  3. 解法(层序遍历):
    算法思路:
  • 第⼀种思路(会超过内存限制):
    既然统计每⼀层的最⼤宽度,我们优先想到的就是利⽤层序遍历,把当前层的结点全部存在队列⾥⾯,利⽤队列的⻓度来计算每⼀层的宽度,统计出最⼤的宽度。但是,由于空节点也是需要计算在内的。因此,我们可以选择将空节点也存在队列⾥⾯。
    这个思路是我们正常会想到的思路,但是极端境况下,最左边⼀条⻓链,最右边⼀条⻓链,我们需要存⼏亿个空节点,会超过最⼤内存限制。
  • 第⼆种思路(利⽤⼆叉树的顺序存储 - 通过根节点的下标,计算左右孩⼦的下标):
    依旧是利⽤层序遍历,但是这⼀次队列⾥⾯不单单存结点信息,并且还存储当前结点如果在数组中存储所对应的下标(在我们学习数据结构 - 堆的时候,计算左右孩⼦的⽅式)。这样我们计算每⼀层宽度的时候,⽆需考虑空节点,只需将当层结点的左右结点的下标相减再加 1 即可。
    但是,这⾥有个细节问题:如果⼆叉树的层数⾮常恐怖的话,我们任何⼀种数据类型都不能存下下标的值。但是没有问题,因为
    • 我们数据的存储是⼀个环形的结构;
    • 并且题⽬说明,数据的范围在 int 这个类型的最⼤值的范围之内,因此不会超出⼀圈;
    • 因此,如果是求差值的话,我们⽆需考虑溢出的情况。
  1. C++代码
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    int widthOfBinaryTree(TreeNode* root) 
    {
        queue<pair<TreeNode*,unsigned int>> q;
        q.push(make_pair(root,1));
        unsigned int cnt=0;
        while(!q.empty())
        {
            int sz=q.size();
            cnt=max(q.back().second-q.front().second+1,cnt);
            while(sz--)
            {
                TreeNode* tmp=q.front().first;
                unsigned int ret=q.front().second;
                q.pop();
                if(tmp->left!=nullptr)
                {
                    q.push(make_pair(tmp->left,2*ret));
                }
                if(tmp->right!=nullptr)
                {
                    q.push(make_pair(tmp->right,2*ret+1));
                }
            }
        }
        return cnt;
    }
};
--------------------------------------------------------------------------------------------
//用数组模拟队列
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    int widthOfBinaryTree(TreeNode* root) 
    {
        vector<pair<TreeNode*,unsigned int>> v;
        v.push_back({root,1});
        unsigned int cnt=0;
        while(v.size())
        {
            auto&[x1,y1]=v[0];
            auto&[x2,y2]=v.back();
            cnt=max(cnt,y2-y1+1);
            vector<pair<TreeNode*,unsigned int>> tmp;
            for(auto&[x,y]:v)
            {
                if(x->left)tmp.push_back({x->left,2*y});
                if(x->right)tmp.push_back({x->right,2*y+1});
            }
            v=tmp;
        }
        return cnt;
    }
};

1.4 在每个树⾏中找最⼤值

  1. 题⽬链接:515. 在每个树⾏中找最⼤值
  2. 题⽬描述:
    在这里插入图片描述
  3. 解法(bfs):
    算法思路:
    层序遍历过程中,在执⾏让下⼀层节点⼊队的时候,我们是可以在循环中统计出当前层结点的最⼤值的。
    因此,可以在 bfs 的过程中,统计出每⼀层结点的最⼤值。
  4. C++代码
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    vector<int> largestValues(TreeNode* root) 
    {
        vector<int> v;
        if(root==nullptr)return v;
        queue<TreeNode*> q;
        q.push(root);
        int maxnum=INT_MIN;
        while(!q.empty())
        {
            int sz=q.size();
            while(sz--)
            {
                TreeNode* tmp=q.front();
                maxnum=max(maxnum,tmp->val);
                q.pop();
                if(tmp->left)
                    q.push(tmp->left);
                if(tmp->right)
                    q.push(tmp->right);
            }
            v.push_back(maxnum);
            maxnum=INT_MIN;
        }
        return v;
    }
};

二、优先级队列(堆)示例:

2.1 最后⼀块⽯头的重量

  1. 题⽬链接:1046. 最后⼀块⽯头的重量
  2. 题⽬描述:
    在这里插入图片描述
  3. 解法(利⽤堆):
    算法思路:
    其实就是⼀个模拟的过程:
    • 每次从⽯堆中拿出最⼤的元素以及次⼤的元素,然后将它们粉碎;
    • 如果还有剩余,就将剩余的⽯头继续放在原始的⽯堆⾥⾯
    重复上⾯的操作,直到⽯堆⾥⾯只剩下⼀个元素,或者没有元素(因为所有的⽯头可能全部抵消了)
    那么主要的问题就是解决:
    • 如何顺利的拿出最⼤的⽯头以及次⼤的⽯头;
    • 并且将粉碎后的⽯头放⼊⽯堆中之后,也能快速找到下⼀轮粉碎的最⼤⽯头和次⼤⽯头;
    这不正好可以利⽤堆的特性来实现嘛?
    • 我们可以创建⼀个⼤根堆;
    • 然后将所有的⽯头放⼊⼤根堆中;
    • 每次拿出前两个堆顶元素粉碎⼀下,如果还有剩余,就将剩余的⽯头继续放⼊堆中;
    这样就能快速的模拟出这个过程。
  4. C++代码
class Solution {
public:
    struct cmp
    {
        bool operator()(int t1,int t2)
        {
            return t1<t2;
        }
    };
    int lastStoneWeight(vector<int>& stones) 
    {
        //priority_queue<int,vector<int>,less<int>> pq;
        priority_queue<int,vector<int>,cmp> pq;
        for(auto&e:stones)
        pq.push(e);
        while(pq.size()>1)
        {
            int tmp1=pq.top();
            pq.pop();
            int tmp2=pq.top();
            pq.pop();
            int tmp=abs(tmp1-tmp2);
            if(tmp==0&&!pq.empty())continue;
            pq.push(tmp);
        }
        return pq.top();
    }
};

2.2 数据流中的第 K ⼤元素

  1. 题⽬链接:703. 数据流中的第 K ⼤元素

  2. 题⽬描述:
    在这里插入图片描述

  3. 解法(优先级队列):
    算法思路:
    我相信,看到 TopK 问题的时候,兄弟们应该能⽴⻢想到「堆」,这应该是刻在⻣⼦⾥的记忆。

  4. C++代码

class KthLargest {
    priority_queue<int,vector<int>,greater<int>> pq;
    int _k;
public:
    KthLargest(int k, vector<int>& nums) 
    {
        _k=k;
        for(auto&e:nums)
        {
            pq.push(e);
            if(pq.size()>_k)pq.pop();
        }
    }
    
    int add(int val) 
    {
        pq.push(val);
        if(pq.size()>_k)pq.pop();
        return pq.top();
    }
};

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

2.3 前 K 个⾼频单词

  1. 题⽬链接:692. 前 K 个⾼频单词
  2. 题⽬描述:
    在这里插入图片描述
  3. 解法(堆):
    算法思路:
    • 稍微处理⼀下原数组:
    a. 我们需要知道每⼀个单词出现的频次,因此可以先使⽤哈希表,统计出每⼀个单词出现的频次;
    b. 然后在哈希表中,选出前 k ⼤的单词(为什么不在原数组中选呢?因为原数组中存在重复的单词,哈希表⾥⾯没有重复单词,并且还有每⼀个单词出现的频次)
    • 如何使⽤堆,拿出前 k ⼤元素:
    a. 先定义⼀个⾃定义排序,我们需要的是前 k ⼤,因此需要⼀个⼩根堆。但是当两个字符串的频次相同的时候,我们需要的是字典序较⼩的,此时是⼀个⼤根堆的属性,在定义⽐较器的时候需要注意!
    ▪ 当两个字符串出现的频次不同的时候:需要的是基于频次⽐较的⼩根堆
    ▪ 当两个字符串出现的频次相同的时候:需要的是基于字典序⽐较的⼤根堆
    b. 定义好⽐较器之后,依次将哈希表中的字符串插⼊到堆中,维持堆中的元素不超过 k 个;
    c. 遍历完整个哈希表后,堆中的剩余元素就是前 k ⼤的元素
  4. C++代码
class Solution {
    typedef pair<string,int> PII;
public:
    struct cmp
    {
        bool operator()(const PII& p1,const PII& p2)
        {
            if(p1.second==p2.second)
            return p1.first<p2.first;// 频次相同,字典序按照⼤根堆的⽅式排列
            return p1.second>p2.second;
        }
    };
    vector<string> topKFrequent(vector<string>& words, int k) 
    {
        priority_queue<PII,vector<PII>,cmp> pq;
        vector<string> v(k);
        unordered_map<string,int> hash;
        for(auto&e:words)hash[e]++;
        for(auto&e:hash)
        {
            pq.push(e);
            if(pq.size()>k)pq.pop();
        }
        for(int i=k-1;i>=0;i--)
        {
            v[i]=pq.top().first;
            pq.pop();
        }
        return v;
    }
};

2.4 数据流的中位数

  1. 题⽬链接:295. 数据流的中位数
  2. 题⽬描述:
    在这里插入图片描述
  3. 解法(利⽤两个堆):
    算法思路:
    这是⼀道关于「堆」这种数据结构的⼀个「经典应⽤」。
    我们可以将整个数组「按照⼤⼩」平分成两部分(如果不能平分,那就让较⼩部分的元素多⼀个),较⼩的部分称为左侧部分,较⼤的部分称为右侧部分:
    • 将左侧部分放⼊「⼤根堆」中,然后将右侧元素放⼊「⼩根堆」中;
    • 这样就能在 O(1) 的时间内拿到中间的⼀个数或者两个数,进⽽求的平均数。
    如下图所⽰:
    在这里插入图片描述

于是问题就变成了「如何将⼀个⼀个从数据流中过来的数据,动态调整到⼤根堆或者⼩根堆中,并且保证两个堆的元素⼀致,或者左侧堆的元素⽐右侧堆的元素多⼀个」为了⽅便叙述,将左侧的「⼤根堆」记为 left ,右侧的「⼩根堆」记为 right ,数据流中来的「数据」记为 x 。
其实,就是⼀个「分类讨论」的过程:

  • 如果左右堆的「数量相同」, left.size() == right.size() :
    a. 如果两个堆都是空的,直接将数据 x 放⼊到 left 中;
    b. 如果两个堆⾮空:
    i. 如果元素要放⼊左侧,也就是 x <= left.top() :那就直接放,因为不会影响我们制定的规则;
    ii. 如果要放⼊右侧
    • 可以先将 x 放⼊ right 中,
    • 然后把 right 的堆顶元素放⼊ left 中 ;
  • 如果左右堆的数量「不相同」,那就是 left.size() > right.size() :
    a. 这个时候我们关⼼的是 x 是否会放⼊ left 中,导致 left 变得过多:
    i. 如果 x 放⼊ right 中,也就是 x >= right.top() ,直接放;
    ii. 反之,就是需要放⼊ left 中:
    • 可以先将 x 放⼊ left 中,
    • 然后把 left 的堆顶元素放⼊ right 中 ;
    只要每⼀个新来的元素按照「上述规则」执⾏,就能保证 left 中放着整个数组排序后的「左半部分」, right 中放着整个数组排序后的「右半部分」,就能在 O(1) 的时间内求出平均数。
  1. C++代码
class MedianFinder 
{
    priority_queue<int,vector<int>,less<int>> left;//大根堆
    priority_queue<int,vector<int>,greater<int>> right;//小根堆
public:
    MedianFinder() 
    {}
    
    void addNum(int num) 
    {
        int n=left.size(),m=right.size();
        if(n==m)
        {
            if(!left.empty()&&num>left.top())
            {
                right.push(num);
                left.push(right.top());
                right.pop();
            }
            else left.push(num);
        }
        else if(n>m)
        {
            if(num<=left.top())
            {
                right.push(left.top());
                left.pop();
                left.push(num);
            }
            else right.push(num);
        }
    }
    
    double findMedian() 
    {
        if(left.size()==right.size())
        return (left.top()+right.top())/2.0;
        else return left.top();
    }
};

/**
 * Your MedianFinder object will be instantiated and called as such:
 * MedianFinder* obj = new MedianFinder();
 * obj->addNum(num);
 * double param_2 = obj->findMedian();
 */

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

气象网格数据与卫星轨道数据如何匹配??

&#x1f3c6;本文收录于《全栈Bug调优(实战版)》专栏&#xff0c;主要记录项目实战过程中所遇到的Bug或因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&am…

IDEA里面的长截图插件

1.我的悲惨经历 兄弟们啊&#xff0c;我太惨了&#xff0c;我刚刚在准备这个继承和多态的学习&#xff0c;写博客的时候想要截图代码&#xff0c;因为这个代码比较大&#xff0c;一张图截取不下来&#xff0c;所以需要长截图&#xff0c;之前使用的qq截图突然间拉胯&#xff0…

栈和队列相互实现(Java)

本篇任务 前篇我们分别介绍了栈和队列&#xff0c;并对其进行了简单的自我实现&#xff0c;本篇我们将通过栈和队列的相互实现来进一步熟悉和运用栈和队列&#xff0c;如下是我们将要完成的题目&#xff1a; 用队列实现栈https://leetcode-cn.com/problems/implement-stack-u…

【2022工业图像异常检测文献】CFLOW-AD: 通过条件归一化流实现实时无监督定位异常检测

CFLOW-AD: Real-Time Unsupervised Anomaly Detection with Localization via Conditional Normalizing Flows 1、Background 虽然最近提出针对此类数据设置的模型在准确性指标上取得了很高的成绩&#xff0c;但它们的复杂性限制了实时处理的能力。 CFLOW-AD由一个经过判别式…

区块链+Web3学习笔记

学习资料来源于B站&#xff1a; 17小时最全Web3教程&#xff1a;ERC20&#xff0c;NFT&#xff0c;Hardhat&#xff0c;CCIP跨链_哔哩哔哩_bilibili 该课程提供的Github代码地址&#xff0c;相关资料详见README.md&#xff1a; Web3_tutorial_Chinese/README.md at main sm…

Netty系列-8 Netty处理粘包和半包问题

1.半包和粘包问题 TCP协议是基于字节流的数据通讯协议&#xff0c;数据被看做是一连串的字节流&#xff1b;不具备边界信息&#xff0c;给接收方带来半包和粘包问题。 半包&#xff1a;TCP传输时&#xff0c;将数据切割成一个个数据包进行传输。接收方一次读取操作&#xff0c…

吉他弹唱打谱软件哪个好用 吉他弹唱制谱教程

吉他这门乐器一直受到大众的欢迎&#xff0c;究其原因&#xff0c;还是因为其成本低廉、易上手的特性。但是吉他是一个入门容易精通难的乐器&#xff0c;想要成为一个资深的吉他玩家&#xff0c;那么就少不了用到一些吉他弹唱打谱软件。今天我们就来说一说吉他弹唱打谱软件哪个…

学习 CSS 新的属性 conic-gradient 实现环形进度条

我们在工作中用到环形进度条的时候&#xff0c;一般都是使用组件库提供的&#xff0c;那么你有没有想过这是怎么实现的呢&#xff1f; <divclass"progress"style"--progress: 80%; --last: 20%"data-progress"80%"></div><style …

【宽搜】2. leetcode 102 二叉树的层序遍历

题目描述 题目链接&#xff1a;二叉树的层序遍历 根据上一篇文章的模板可以直接写代码&#xff0c;需要改变的就是将N叉树的child改为二叉树的left和right。 代码 class Solution { public:vector<vector<int>> levelOrder(TreeNode* root) {vector<vector&…

k8s的学习和使用

为什么用k8s&#xff0c;不用docker&#xff1f; k8s更适合复杂的微服务架构和大规模的容器应用。 Pods(Pod) Pod是k8s最小可部署单元&#xff0c;他包含一个或多个相关容器。这些容器共享网络命名空间和存储卷&#xff0c;他们通常协同工作来构成一个应用程序。 Serv…

开启AI新篇章:探索GPT-4与大模型!订阅方案!简单支付!

开启AI新篇章&#xff1a;探索GPT-4的无限可能 随着人工智能技术的飞速发展&#xff0c;我们正处于一个前所未有的变革时代。作为人工智能领域的领导者&#xff0c;OpenAI 推出的GPT-4&#xff0c;以其卓越的自然语言处理能力和强大的计算潜力&#xff0c;引发了行业内外的广泛…

深入浅出MySQL

深入浅出MySQL 以下内容参考自 《MySQL是怎样运行的&#xff1a;从根儿上理解MySQL》一书&#xff0c;强烈推荐 存储引擎 对于不同的表可以设置不同的存储引擎 CREATE TABLE tableName (xxxx ) ENGINE 引擎名称; # 修改 ALTER TABLE tableName ENGINE xxx; 编码格式 my…

(C语言贪吃蛇)10.贪吃蛇向右自行行走

目录 前言 本节内容 实现效果 修改后的代码 其他封装函数&#xff1a; 运行效果 总结 前言 我们上节讲解了关于贪吃蛇撞墙然后死翘翘重新初始化蛇身的操作&#xff0c;主要是关于程序初始化释放内存的操作&#xff0c;不理解的再去看看&#x1f618;(贪吃蛇撞墙找死详解)。…

SpringBoot技术栈:构建高效古典舞交流平台

第二章 相关技术介绍 2.1Java技术 Java是一种非常常用的编程语言&#xff0c;在全球编程语言排行版上总是前三。在方兴未艾的计算机技术发展历程中&#xff0c;Java的身影无处不在&#xff0c;并且拥有旺盛的生命力。Java的跨平台能力十分强大&#xff0c;只需一次编译&#xf…

openpnp - 吸嘴校正失败的opencv参数分析

文章目录 openpnp - 吸嘴校正失败的opencv参数分析概述笔记阶段验证 - N2吸嘴校验完NT1NT2 阶段验证 - 底部相机高级校验完NT1NT2 参数比对保存 “阶段验证 - N2吸嘴校验完” 的NT1/NT2图像重建参数检测环境NT1ok的3个参数值NT1err的3个参数值NT2ok的3个参数值NT2err的3个参数值…

如何入门运动规划算法? 50篇教程教你手把手推导公式! 实现代码!

经常听到有想入门规划算法的同学说: 各路教程不成体系, 不知从何学起? 网上的规划算法教程资料确实很多. 但是东一篇frenet, 西一篇QP优化, 大部分都是各路大佬写给自己看的学习笔记, 杂乱无章不成体系. 有没有给小白看的, 完整成体系的运动规划算法教程呢? 穷学生囊中羞…

Redis入门第四步:Redis发布与订阅

欢迎继续跟随《Redis新手指南&#xff1a;从入门到精通》专栏的步伐&#xff01;在本文中&#xff0c;我们将深入探讨Redis的发布与订阅&#xff08;Pub/Sub&#xff09;模式。这是一种强大的消息传递机制&#xff0c;适用于各种实时通信场景&#xff0c;如聊天应用、实时通知和…

反调试—1

IsDebuggerPresent() CheckRemoteDebuggerPresent() 其内部实际调用NtQueryInformationProcess() bool _stdcall ThreadCall() {while (true){BOOL pbDebuggerPresent FALSE;CheckRemoteDebuggerPresent(GetCurrentProcess(), &pbDebuggerPresent);if (pbDebuggerPres…

Redis数据库与GO(一):安装,string,hash

安装包地址&#xff1a;https://github.com/tporadowski/redis/releases 建议下载zip版本&#xff0c;解压即可使用。解压后&#xff0c;依次打开目录下的redis-server.exe和redis-cli.exe&#xff0c;redis-cli.exe用于输入指令。 一、基本结构 如图&#xff0c;redis对外有个…

Netgear-WN604 downloadFile.php 信息泄露复现(CVE-2024-6646)

0x01 产品描述&#xff1a; NETGEAR WN604是一款功能强大的双频AC1200无线路由器,非常适合中大型家庭和企业使用。它支持最新的802.11ac无线标准,能提供高达1200Mbps的无线传输速度。路由器具备千兆有线网口和3个100Mbps有线网口,可满足有线和无线设备的接入需求。此外,它还内置…