【算法题攻略】BFS 解决FloodFill 算法、最短路问题、多源BFS 和 拓扑排序

文章目录

  • [一、BFS 解决 FloodFill 算法](#一、BFS 解决 FloodFill 算法)
    • [1. FloodFill 算法 的简介(如何用BFS实现)](#1. FloodFill 算法 的简介(如何用BFS实现))
    • [2. 图像渲染(如何用代码实现BFS的过程)](#2. 图像渲染(如何用代码实现BFS的过程))
    • [3. 岛屿数量](#3. 岛屿数量)
    • [4. 练习题:岛屿的最大面积(思路同:岛屿数量)](#4. 练习题:岛屿的最大面积(思路同:岛屿数量))
    • [5. 被围绕的区域(思想:正难则反)](#5. 被围绕的区域(思想:正难则反))
  • [二、BFS 解决最短路问题](#二、BFS 解决最短路问题)
    • [1. BFS 解决最短路问题的简介(含解题思路)](#1. BFS 解决最短路问题的简介(含解题思路))
    • [2. 迷宫中离入口最近的出口](#2. 迷宫中离入口最近的出口)
    • [3. 最小基因变化](#3. 最小基因变化)
  • 三、多源BFS
    • [1. 多源最短路问题的简介](#1. 多源最短路问题的简介)
    • [2. 01 矩阵](#2. 01 矩阵)
    • [3. 飞地的数量(思想:正难则反)](#3. 飞地的数量(思想:正难则反))
  • [四、BFS 解决拓扑排序](#四、BFS 解决拓扑排序)
    • [1. 拓扑排序简介](#1. 拓扑排序简介)
    • [2. 课程表(用数据结构实现图,再进行拓扑排序)](#2. 课程表(用数据结构实现图,再进行拓扑排序))
    • [3. 课程表 II](#3. 课程表 II)

一、BFS 解决 FloodFill 算法

1. FloodFill 算法 的简介(如何用BFS实现)

Flood Fill(泛洪填充) 是一种经典的图像处理算法,其核心思想非常直观:从一个起始点出发,向四周扩散,将与起点颜色相同(或在容差范围内)的所有连通区域全部替换为新颜色。

(1) 核心原理与连通方式

算法通过检查当前像素的上下左右(或八个方向)邻居,判断其是否符合填充条件。其连通性主要分为两种:

  • 四连通(4-directional): 只向上、下、左、右四个方向扩散。用于防止颜色"渗透"过仅对角线接触的缝隙。

  • 八连通(8-directional): 向周围八个方向(含对角线)扩散。填充更彻底,但可能会"穿过"仅对角接触的角落。

(2) 实现方式:DFS 与 BFS

代码实现上,主要依赖两种搜索策略:

  • 深度优先搜索(DFS,即递归/栈): 代码最简洁(递归)。找到一个点就立即深入其邻居,直到尽头再回溯。

    • 缺点:在填充超大区域(如数万像素)时,递归层数过深极易导致栈溢出(Stack Overflow)。
  • 广度优先搜索(BFS,即队列): 使用队列管理待处理的点。从起点开始,逐层向外"扫描"。

    • 优点:避免了递归深度限制,处理大图像更安全、稳定。

2. 图像渲染(如何用代码实现BFS的过程)

733. 图像渲染

示例 1:

  • 输入:image = \[1,1,1,1,1,0,1,0,1],sr = 1, sc = 1, color = 2

  • 输出:\[2,2,2,2,2,0,2,0,1]

  • 解释:在图像的正中间,坐标 (sr,sc)=(1,1) (即红色像素),在路径上所有符合条件的像素点的颜色都被更改成相同的新颜色(即蓝色像素)。 注意,右下角的像素 没有更改为2,因为它不是在上下左右四个方向上与初始点相连的像素点。
    示例 2:

  • 输入:image = \[0,0,0,0,0,0], sr = 0, sc = 0, color = 0

  • 输出:\[0,0,0,0,0,0]

  • 解释:初始像素已经用 0 着色,这与目标颜色相同。因此,不会对图像进行任何更改。
    提示:

  • m == image.length

  • n == imagei.length

  • 1 <= m, n <= 50

  • 0 <= imageij, color < 216

  • 0 <= sr < m

  • 0 <= sc < n

  • 代码实现:
cpp 复制代码
class Solution {
public:
    int in_x[4] = {0, 0, 1, -1};
    int in_y[4] = {1, -1, 0, 0};

    vector<vector<int>> floodFill(vector<vector<int>>& image, int sr, int sc, int color) {
        int img_x = image.size();
        int img_y = image[0].size();
        int init_color = image[sr][sc];

        if(init_color == color)
            return image;

        // 存储元素下标的 数列
        queue< pair<int, int> > que_index;

        que_index.push({sr, sc});
        image[sr][sc] = color;
        
        // 循环进行 BFS搜索
        while(!que_index.empty())
        {
            pair<int, int> pa_xy = que_index.front();
            que_index.pop();

            for(int i = 0; i < 4; i++)
            {
                int x = pa_xy.first + in_x[i];
                int y = pa_xy.second + in_y[i];

                if(x >= 0 && x < img_x && y >= 0 && y < img_y && image[x][y] == init_color)
                {
                    que_index.push({x, y});
                    image[x][y] = color;
                }
            }
        }
        return image;
    }
};

3. 岛屿数量

200. 岛屿数量

示例 1:

  • **输入:
    grid = \['1','1','1','1','0',
    '1','1','0','1','0',
    '1','1','0','0','0',

    '0','0','0','0','0'

    ]**

  • 输出:1
    示例 2:

  • **输入:
    grid = \['1','1','0','0','0',
    '1','1','0','0','0',
    '0','0','1','0','0',

    '0','0','0','1','1'

    ]**

  • 输出:3
    提示:

  • m == grid.length

  • n == gridi.length

  • 1 <= m, n <= 300

  • gridij 的值为 '0' 或 '1'

  • 代码实现(采用解法一的思想):
cpp 复制代码
class Solution {
public:
    int dx[4] = {0, 0, 1, -1};
    int dy[4] = {1, -1, 0, 0};

    int numIslands(vector<vector<char>>& grid) {
        int m = grid.size();
        int n = grid[0].size();
        // 记录岛屿数量
        int count = 0;

        // 存储元素下标的 数列
        queue< pair<int, int> > que_index;

        for(int i = 0; i < m; i++)
        {
            for(int j = 0; j < n; j++)
            {
                // 发现 '1', 进行BFS,找出'1' 的连通块,找的过程中,将找过的 '1' 置为 '0'
                if(grid[i][j] == '1')
                {
                    count++;
                    que_index.push({i, j});
                    grid[i][j] = '0';

                    while(!que_index.empty())
                    {
                        pair<int, int> pa_xy = que_index.front();
                        que_index.pop();

                        for(int k = 0; k < 4; k++)
                        {
                            int x = pa_xy.first + dx[k];
                            int y = pa_xy.second + dy[k];

                            if(x >= 0 && x < m && y >= 0 && y < n && grid[x][y] == '1')
                            {
                                que_index.push({x, y});
                                grid[x][y] = '0';
                            }
                        }
                    }
                }
            }
        }

        return count;
    }
};

4. 练习题:岛屿的最大面积(思路同:岛屿数量)

695. 岛屿的最大面积

5. 被围绕的区域(思想:正难则反)

130. 被围绕的区域

  • 代码实现:
cpp 复制代码
class Solution {
public:
    int dx[4] = {0, 0, 1, -1};
    int dy[4] = {1, -1, 0, 0};

    void BFS(vector<vector<char>>& _board, vector<vector<bool>>& _vec_bool, int _i, int _j)
    {
        int m = _board.size();
        int n = _board[0].size();

        queue<pair<int, int>> que_index;
        que_index.push({_i, _j});
        _vec_bool[_i][_j] = true;

        while(!que_index.empty())
        {
            pair<int, int> pa_xy = que_index.front();
            que_index.pop();

            for(int i = 0; i < 4; i++)
            {
                int x = pa_xy.first + dx[i];
                int y = pa_xy.second + dy[i];
                if(x >= 0 && x < m && y >= 0 && y < n && _board[x][y] == 'O' && _vec_bool[x][y] == 0)
                {
                    que_index.push({x, y});
                    _vec_bool[x][y] = true;
                }
            }
        }
    }

    void solve(vector<vector<char>>& board) {
        int m = board.size();
        int n = board[0].size();
        vector<vector<bool>> vec_bool(m, vector<bool>(n, false));

        // 先利⽤ bfs 将与边缘相连的 '0' 区域做上标记(将对应位置的bool修改为 1)
        for(int i = 0; i < m; i++)
        {
            if(i == 0 || i == m-1) // 只有第一排 和 最后一排遍历整排
            {
                for(int j = 0; j < n; j++)
                {
                    if(board[i][j] == 'O' && vec_bool[i][j] == 0)
                        BFS(board, vec_bool, i, j);
                }
            }
            else // 非第一排 和 最后一排只遍历该排首尾元素
            {
                if(board[i][0] == 'O' && vec_bool[i][0] == 0)
                    BFS(board, vec_bool, i, 0);
                if(board[i][n-1] == 'O' && vec_bool[i][n-1] == 0)
                    BFS(board, vec_bool, i, n-1);
            }
        }

        // 将没有标记过的 '0'(对应位置的bool值仍然是false 的'0') 修改成 'X' 即可
        for(int i = 0; i < m; i++)
        {
            for(int j = 0; j < n; j++)
            {
                if(board[i][j] == 'O' && vec_bool[i][j] == 0)
                    board[i][j] = 'X';
            }
        }
    }
};

二、BFS 解决最短路问题

1. BFS 解决最短路问题的简介(含解题思路)

针对边权均为1(即边权全都相同,每两点间的距离都相同)的最短路问题,广度优先搜索(BFS) 是绝对最优解。以下是其核心简介:

(1) 核心原理:队列与"波纹效应"

BFS 利用队列(FIFO) 的先进先出特性,从起点开始,像水波一样逐层向外扩散。

  • 第 1 层:距离起点为 1 的所有节点;

  • 第 2 层:距离起点为 2 的所有节点;

  • ......

由于队列保证了"先访问到的节点,其距离一定不大于后访问到的节点",因此 当某个节点第一次被访问(入队)时,所走的路径一定是从起点到该节点的最短路径(即第一次命中即为最优解)。

(2) 关键注意事项(避坑指南)

必须判重(标记访问):若不加 哈希表hash(或者 其它能用来标记访问的数据结构),节点会重复入队,导致死循环或指数级复杂度。标记时机必须是入队时(而非出队时),否则同一节点可能被多次入队,破坏距离最短性。

2. 迷宫中离入口最近的出口

1926. 迷宫中离入口最近的出口

  • 代码实现:
cpp 复制代码
class Solution {
public:
    int dx[4] = {0, 0, 1, -1};
    int dy[4] = {1, -1, 0, 0};

    int nearestExit(vector<vector<char>>& maze, vector<int>& entrance) {
        int m = maze.size();
        int n = maze[0].size();
        
        // 存储元素下标的数列
        queue< pair<int, int> > que;
        // 标记该位置是否被搜索过的bool数组
        vector<vector<bool>> vec_bool(m, vector<bool>(n, false));
        
        // 准备阶段
        que.push({entrance[0], entrance[1]});
        vec_bool[entrance[0]][entrance[1]] = true;

        int number = 0; // 记录BFS的搜索轮次
        
        // 进行多轮BFS
        while(!que.empty())
        {
            // 计算该轮 要进行几次BFS
            int count = que.size();
            number++;
            while(count--)
            {
                pair<int, int> pa_xy = que.front();
                que.pop();

                for(int i = 0; i < 4; i++)
                {
                    int x = pa_xy.first + dx[i];
                    int y = pa_xy.second + dy[i];

                    if(x >= 0 && x < m && y >= 0 && y < n && maze[x][y] == '.' && vec_bool[x][y] == false)
                    {
                        // 到达出口,返回最短路径(也就是BFS轮数)
                        if(x == 0 || x == m-1 || y == 0 || y == n-1) 
                            return number;
                        que.push({x, y});
                        vec_bool[x][y] = true;
                    }
                }
            }
        }
        return -1;
    }
};

3. 最小基因变化

433. 最小基因变化

  • 代码实现:
cpp 复制代码
class Solution {
public:
    // 比较两个字符串 是否只有一个字符的差异
    bool com_string(const string &str1, const string &str2)
    {
        int count = 0;
        for(int i = 0; i < 8; i++)
        {
            if(str1[i] != str2[i])
                count++;
        }
        if(count == 1)
            return true;
        return false;
    }

    int minMutation(string startGene, string endGene, vector<string>& bank) {
        if(startGene == endGene)
            return 0;

        int m = bank.size();

        // 存储字符串的 队列
        queue<string> que;
        // 记录基因库每个位置是否被搜索过
        vector<bool> vec_bool(m, false);

        // 将起始字符串 入队
        que.push(startGene);
        // 记录BFS的轮次
        int number = 0;
        // 进行多轮BFS
        while(!que.empty())
        {
            number++;
            // 计算该轮 要进行多少次BFS
            int count = que.size();
            while(count--)
            {
                string tmp = que.front();
                que.pop();
                // 找出所有基因库bank中一次变换能变成的 字符串
                for(int i = 0; i < m; i++)
                {
                    if(vec_bool[i] == false && com_string(tmp, bank[i]))
                    {
                        if(bank[i] == endGene) // 最初字符串变换到endGene时,BFS的轮次就是最少变化次数
                            return number;
                        que.push(bank[i]);
                        vec_bool[i] = true;
                    }
                }
            }
        }
        return -1;
    }
};

三、多源BFS

1. 多源最短路问题的简介

针对边权均为1的多源最短路问题(即有多个起点),BFS 同样是最优解。其核心思想是"多源头同时点火"。

(1) 核心原理:虚拟超级源点

多源 BFS 不需要对每个起点分别跑一次 BFS(那样会超时)。它的技巧是在逻辑上创建一个"虚拟超级源点":

  • 将这个虚拟源点用 0 权值的边连接到所有真实的起点。

  • 从虚拟源点开始跑单源 BFS。

落实到代码中更简单:初始化队列时,一次性将所有起点全部入队。 这样,BFS 的"波纹"从所有起点同时向外扩散,谁先扩散到某个节点,该节点到最近起点的距离就是最短的。

(2) 关键注意事项(避坑指南)

必须判重(标记访问):若不加 哈希表hash(或者 其它能用来标记访问的数据结构),节点会重复入队,导致死循环或指数级复杂度。标记时机必须是入队时(而非出队时),否则同一节点可能被多次入队,破坏距离最短性。

2. 01 矩阵

542. 01 矩阵

  • 代码示例:
cpp 复制代码
class Solution {
public:
    int dx[4] = {0, 0, 1, -1};
    int dy[4] = {1, -1, 0, 0};

    vector<vector<int>> updateMatrix(vector<vector<int>>& mat) {
        int m = mat.size();
        int n = mat[0].size();

        // 存储元素下标的队列
        queue<pair<int, int>> que;
        // 标记元素为1的位置是否被搜索过的 bool数组
        vector<vector<bool>> vec_bool(m, vector<bool>(n, false));
        // 记录每个位置到最近0的距离
        vector<vector<int>> distance(m, vector<int>(n, 0));
        
        // 遍历数组,把所有0元素的位置坐标入队列
        for(int i = 0; i < m; i++)
        {
            for(int j = 0; j < n; j++)
            {
                if(mat[i][j] == 0)
                    que.push({i, j});
            }
        }
        
        // 记录BFS的轮次
        int number = 0;
        // 进行多轮BFS
        while(!que.empty())
        {
            number++;
            // 记录此轮 进行多少次BFS
            int count = que.size();
            while(count--)
            {
                pair<int, int> pa_xy = que.front();
                que.pop();

                for(int i = 0; i < 4; i++)
                {
                    int x = pa_xy.first + dx[i];
                    int y = pa_xy.second + dy[i];

                    if(x >= 0 && x < m && y >= 0 && y < n && mat[x][y] == 1 &&  vec_bool[x][y] == false)
                    {
                        que.push({x, y});
                        vec_bool[x][y] = true;
                        distance[x][y] = number; // 该轮找到的元素1,它们到最近0的距离 就是BFS的轮次
                    }
                }
            }
        }
        return distance;
    }
};

3. 飞地的数量(思想:正难则反)

1020. 飞地的数量

  • 代码演示:
cpp 复制代码
class Solution {
public:
    int dx[4] = {0, 0, 1, -1};
    int dy[4] = {1, -1, 0, 0};

    int numEnclaves(vector<vector<int>>& grid) {
        int m = grid.size();
        int n = grid[0].size();

        queue<pair<int, int>> que;
        vector<vector<bool>> vec_bool(m, vector<bool>(n, false));

        // 1. 把边缘上的 1 加⼊到队列中
        for(int i = 0; i < m; i++)
        {
            for(int j = 0; j < n; j++)
            {
                if(i == 0 || i == m - 1 || j == 0 || j == n - 1)
                {
                    if(grid[i][j] == 1)
                    {
                        que.push({i, j});
                        vec_bool[i][j] = true;
                    }
                }
            }
        }
        
        //  2. 多源 bfs(将所有与边缘 1 联通的1标记为true)
        while(!que.empty())
        {
            pair<int, int> pa_xy = que.front();
            que.pop();

            for(int i = 0; i < 4; i++)
            {
                int x = pa_xy.first + dx[i];
                int y = pa_xy.second + dy[i];

                if(x >= 0 && x < m && y >= 0 && y < n && grid[x][y] == 1 && vec_bool[x][y] == false)
                {
                    que.push({x, y});
                    vec_bool[x][y] = true;
                }
            }
        }
        
        // 3. 遍历数组,统计所有不与边缘1 联通的1
        int number = 0;
        for(int i = 0; i < m; i++)
        {
            for(int j = 0; j < n; j++)
            {
                if(grid[i][j] == 1 && vec_bool[i][j] == false)
                    number++;
            }
        }
        return number;
    }
};

四、BFS 解决拓扑排序

1. 拓扑排序简介

(1) 有向无环图(DAG图)

  • 入度(入度 - Indegree): 进入一个顶点的边的数量。它代表前置依赖项的数量(在拓扑排序中,依赖项在之前完成)。

  • 出度(出度 - Outdegree): 离开一个顶点的边的数量。它代表依赖于当前顶点的后续任务的数量。

(2) AOV网(Activity On Vertex Network,顶点表示活动的网络)就是你刚才一直在讨论的拓扑排序的"应用载体"。

简单来说:把有向无环图(DAG)用于描述工程流程时,这张图就叫做 AOV 网。

为了帮你彻底打通概念,我们把 AOV 网和之前聊的入度/出度、拓扑排序串在一起:

  • AOV 网的核心定义(核心理念)

顶点(Vertex): 表示一个活动(Activity)或任务(如"打地基"、"安装门窗")。

有向边(Edge): 表示活动之间的先后依赖关系。如果存在边 A → B,就意味着 "A 必须在 B 之前完成"。

注意: AOV 网必须是有向无环图(DAG)。一旦出现环,就意味着活动之间产生了"死锁"式的循环依赖(A等B,B等C,C等A),工程永远无法开工。

  • 入度/出度在 AOV 网中的"工程含义"

把抽象的图论术语翻译成项目管理的语言,你会瞬间明白它们的实际价值:

图论术语 AOV 网中的工程含义 在项目中的角色
入度(Indegree) 该活动紧前任务(前置依赖)的数量。 入度 = 0 的活动,代表没有前置条件,可以立即开工(如项目启动会)。
出度(Outdegree) 该活动紧后任务(后续依赖)的数量。 出度 = 0 的活动,代表没有后续环节,是整个项目的收尾节点(如项目验收)。

在 Kahn 算法中,每完成一个入度为 0 的活动,就相当于"该活动已完工",此时将它所有后继活动的入度减 1(表示解除了对后继活动的唯一阻碍)。

(3)拓扑排序

找出做事情的先后顺序,拓扑排序的结果可能不是唯一的

拓扑排序的本质,就是将有向无环图(DAG)中的所有顶点排成一个线性序列

  • 如何排序?
    • (1)找出图中入度为 0 的点,然后输出
    • (2)删除与该点连接的边
    • (3)重复 1、2 操作,直到图为空(图中没有点) 或者 图中没有入度为0的点为止(图中存在环)

(4)拓扑排序可以用来检测一个有向图是否存在环(有环的话,拓扑排序就无法完成)

2. 课程表(用数据结构实现图,再进行拓扑排序)

207. 课程表

  • 代码实现:
cpp 复制代码
class Solution {
public:
    bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
        // 1. 建图
        // (1)邻接表(key: 课程 ; value: key出度指向的所有课程)
        unordered_map<int, vector<int>> edges;
        // (2)记录每个点的入度数量(初始每个点的入度数量为0)
        unordered_map<int, int> in;
        for(int i = 0; i < numCourses; i++)
        {
            in.insert({i, 0});
        }

        for(auto it : prerequisites)
        {
            // 假设 it为[0, 1], 代表0 依赖 1,也就是1 -> 0

            // 1这个点 出度方向的边指向0
            auto ret = edges.find(it[1]);
            if(ret == edges.end())
            {
                edges.insert({it[1], vector<int>(1, it[0])});
            }
            else
                ret->second.push_back(it[0]);
            
            // 0这个点的入度+1
            in[it[0]]++;
        }

        // 2. 进行拓扑排序(判断有没有环)
        int count = 0;  // 记录BFS的次数
        // 存储入度为0的 课程
        queue<int> que;
        for(auto it : in)
        {
            if(it.second == 0)
                que.push(it.first);
        }
        
        // 循环进行BFS
        while(!que.empty())
        {
            count++;
            // 取出队头元素
            int tmp = que.front();
            que.pop();

            // 查邻接表,将与队头元素相连的顶点的入度-1
            auto tmp_vec = edges.find(tmp);
            if(tmp_vec != edges.end())
            {
                for(auto it : tmp_vec->second)
                {
                    in[it]--; 
                    // 判断相连的顶点的入度是否减成0了,
                    // 如果减成 0,将相连的顶点 入队列
                    if(in[it] == 0)
                        que.push(it);
                }
            }
        }

        // 3. 判断 count 的次数
        if(count == numCourses) // 对numCourses门课程 都进行了拓扑排序
            return true;
        else                    // 图中存在环,无法对所有课程都进行拓扑排序
            return false;
    }
};

3. 课程表 II

210. 课程表 II

  • 代码解析:
cpp 复制代码
class Solution {
public:
    vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) 
    {
        // 1. 建图
        // (1)邻接表(key: 课程 ; value: key出度指向的所有课程)
        unordered_map<int, vector<int>> edges;
        // (2)记录每个点的入度数量(初始每个点的入度数量为0)
        unordered_map<int, int> in;
        for(int i = 0; i < numCourses; i++)
        {
            in.insert({i, 0});
        }

        for(auto it : prerequisites)
        {
            // 假设 it为[0, 1], 代表0 依赖 1,也就是1 -> 0

            // 1这个点 出度方向的边指向0
            auto ret = edges.find(it[1]);
            if(ret == edges.end())
            {
                edges.insert({it[1], vector<int>(1, it[0])});
            }
            else
                ret->second.push_back(it[0]);
            
            // 0这个点的入度+1
            in[it[0]]++;
        }

        // 2. 进行拓扑排序(判断有没有环)
        int count = 0;  // 记录BFS的次数
        // 存储入度为0的 课程
        queue<int> que;
        for(auto it : in)
        {
            if(it.second == 0)
                que.push(it.first);
        }
        
        // 存储拓扑排序的结果
        vector<int> sort_result;
        
        // 循环进行BFS
        while(!que.empty())
        {
            count++;
            // 取出队头元素
            int tmp = que.front();
            que.pop();
            sort_result.push_back(tmp);

            // 查邻接表,将与队头元素相连的顶点的入度-1
            auto tmp_vec = edges.find(tmp);
            if(tmp_vec != edges.end())
            {
                for(auto it : tmp_vec->second)
                {
                    in[it]--; 
                    // 判断相连的顶点的入度是否减成0了,
                    // 如果减成 0,将相连的顶点 入队列
                    if(in[it] == 0)
                        que.push(it);
                }
            }
        }

        // 3. 判断 count 的次数
        if(count == numCourses) // 对numCourses门课程 都进行了拓扑排序
            return sort_result;
        else                    // 图中存在环,无法对所有课程都进行拓扑排序
            return vector<int>();
    }
};

相关推荐
Adios7943 小时前
设置交集大小至少为2
数据结构·算法·leetcode
程序喵大人6 小时前
【C++进阶】STL容器与迭代器 - 01 STL 容器先解决元素放在哪里
开发语言·c++·stl
野生风长10 小时前
C++入门基础:从命名空间到引用与指针的全面解析
开发语言·c++
来一碗刘肉面10 小时前
栈的应用(表达式求值)
数据结构·算法
xiaowang1234shs11 小时前
怪兽轻断食技术深度测评:从断食计时引擎到AI识别算法的工程实践解析
数据库·人工智能·算法·macos·机器学习·p2p·visual studio
小果因子实验室11 小时前
量化研究--策略迁移算法1研究
算法
Escalating_xu11 小时前
C++可变参数模板与引用折叠精讲
开发语言·c++
Web极客码11 小时前
如何用三段式确定性剪枝,为 LLM Agent 砍掉 35% 的 Token 成本?
服务器·人工智能·算法·机器学习