LeetCode刷题总结 | 图论2—深度优先搜索广度优先搜索较为复杂应用

news2024/9/21 22:39:25

深搜广搜的标准模版在图论1已经整理过了,也整理了几个标准的套模板的题目,这一小节整理一下较为复杂的DFS&BFS应用类问题。

417 太平洋大西洋水流问题(medium)

有一个 m × n 的矩形岛屿,与 太平洋 和 大西洋 相邻。 “太平洋” 处于大陆的左边界和上边界,而 “大西洋” 处于大陆的右边界和下边界。

这个岛被分割成一个由若干方形单元格组成的网格。给定一个 m x n 的整数矩阵 heights , heights[r][c] 表示坐标 (r, c) 上单元格 高于海平面的高度 。

岛上雨水较多,如果相邻单元格的高度 小于或等于 当前单元格的高度,雨水可以直接向北、南、东、西流向相邻单元格。水可以从海洋附近的任何单元格流入海洋。

返回网格坐标 result 的 2D 列表 ,其中 result[i] = [ri, ci] 表示雨水从单元格 (ri, ci) 流动 既可流向太平洋也可流向大西洋 。
在这里插入图片描述
思路:这道题本身不难,关键是理解题意。简单来说就是:雨水只能从高的地方流向低的地方,求二维表格中哪些坐标的雨水既可以流入太平洋又可以流入大西洋。详细解析

那么一个比较直白的想法,其实就是 遍历每个点,然后看这个点 能不能同时到达太平洋和大西洋。遍历每一个节点,是 m ∗ n m * n mn,遍历每一个节点的时候,都要做深搜,深搜的时间复杂度是: m ∗ n m * n mn,那么整体时间复杂度 就是$ O(m^2 * n^2) $,这是一个四次方的时间复杂度,显然没有进行任何优化,大概率会超时。

那么我们可以 反过来想,从太平洋边上的节点 逆流而上,将遍历过的节点都标记上。 从大西洋的边上节点 逆流而长,将遍历过的节点也标记上。 然后两方都标记过的节点就是既可以流太平洋也可以流大西洋的节点。

从太平洋边上节点出发,如图:
在这里插入图片描述

从大西洋边上节点出发,如图:

在这里插入图片描述
代码实现:

class Solution {
private:
    int dir[4][2] = {-1, 0, 0, -1, 1, 0, 0, 1}; // 保存四个方向

    // 从低向高遍历,注意这里visited是引用,即可以改变传入的pacific和atlantic的值
    void dfs(vector<vector<int>>& heights, vector<vector<bool>>& visited, int x, int y) {
        if (visited[x][y]) return;
        visited[x][y] = true;
        for (int i = 0; i < 4; i++) { // 向四个方向遍历
            int nextx = x + dir[i][0];
            int nexty = y + dir[i][1];
            // 超过边界
            if (nextx < 0 || nextx >= heights.size() || nexty < 0 || nexty >= heights[0].size()) continue;
            // 高度不合适,注意这里是从低向高判断
            if (heights[x][y] > heights[nextx][nexty]) continue;

            dfs (heights, visited, nextx, nexty);
        }
        return;

    }

public:

    vector<vector<int>> pacificAtlantic(vector<vector<int>>& heights) {
        vector<vector<int>> result;
        int n = heights.size();
        int m = heights[0].size(); // 这里不用担心空指针,题目要求说了长宽都大于1

        // 记录从太平洋边出发,可以遍历的节点
        vector<vector<bool>> pacific = vector<vector<bool>>(n, vector<bool>(m, false));

        // 记录从大西洋出发,可以遍历的节点
        vector<vector<bool>> atlantic = vector<vector<bool>>(n, vector<bool>(m, false));

        // 从最上最下行的节点出发,向高处遍历
        for (int i = 0; i < n; i++) {
            dfs (heights, pacific, i, 0); // 遍历最左列,接触太平洋 
            dfs (heights, atlantic, i, m - 1); // 遍历最右列,接触大西 
        }

        // 从最左最右列的节点出发,向高处遍历
        for (int j = 0; j < m; j++) {
            dfs (heights, pacific, 0, j); // 遍历最上行,接触太平洋
            dfs (heights, atlantic, n - 1, j); // 遍历最下行,接触大西洋
        }
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                // 如果这个节点,从太平洋和大西洋出发都遍历过,就是结果
                if (pacific[i][j] && atlantic[i][j]) result.push_back({i, j});
            }
        }
        return result;
    }
};
  • 时间复杂度:O(n * m)

关于dfs函数搜索的过程 时间复杂度是 O(n * m)。

关键看主函数,那么每次dfs的时候,上面还是有for循环的。

第一个for循环,时间复杂度是: n ∗ ( n ∗ m ) n * (n * m) n(nm)

第二个for循环,时间复杂度是: m ∗ ( n ∗ m ) m * (n * m) m(nm)

所以本题看起来 时间复杂度好像是 : n ∗ ( n ∗ m ) + m ∗ ( n ∗ m ) = ( m ∗ n ) ∗ ( m + n ) n * (n * m) + m * (n * m) = (m * n) * (m + n) n(nm)+m(nm)=(mn)(m+n)

其实这是一个误区,大家再自己看 dfs函数的实现,其实 有visited函数记录 走过的节点,而走过的节点是不会再走第二次的。

所以 调用dfs函数,只要参数传入的是数组pacific,那么地图中 每一个节点其实就遍历一次,无论你调用多少次。

同理,调用 dfs函数,只要 参数传入的是 数组atlantic,地图中每个节点也只会遍历一次。

所以,以下这段代码的时间复杂度是 2 ∗ n ∗ m 2 * n * m 2nm。 地图用每个节点就遍历了两次,参数传入pacific的时候遍历一次,参数传入atlantic的时候遍历一次。

// 从最上最下行的节点出发,向高处遍历
for (int i = 0; i < n; i++) {
    dfs (heights, pacific, i, 0); // 遍历最上行,接触太平洋
    dfs (heights, atlantic, i, m - 1); // 遍历最下行,接触大西洋
}

// 从最左最右列的节点出发,向高处遍历
for (int j = 0; j < m; j++) {
    dfs (heights, pacific, 0, j); // 遍历最左列,接触太平洋
    dfs (heights, atlantic, n - 1, j); // 遍历最右列,接触大西洋
}

那么本题整体的时间复杂度其实是: 2 ∗ n ∗ m + n ∗ m 2 * n * m + n * m 2nm+nm,所以最终时间复杂度为 O(n * m) 。

  • 空间复杂度为:O(n * m)

827 最大人工岛(hard)

给你一个大小为 n x n 二进制矩阵 grid 。最多 只能将一格 0 变成 1 。

返回执行此操作后,grid 中最大的岛屿面积是多少?

岛屿 由一组上、下、左、右四个方向相连的 1 形成。

思路:和图论1中的模板题相比,这道题的思维难度的确比较大。详细解析

如果使用暴力解法的话,应该是遍历地图尝试将每一个 0 改成1,然后去搜索地图中的最大的岛屿面积。

计算地图的最大面积:遍历地图 + 深搜岛屿,时间复杂度为 n * n。(其实使用深搜还是广搜都是可以的,其目的就是遍历岛屿做一个标记,相当于染色,那么使用哪个遍历方式都行,以下我用深搜来讲解)

每改变一个0的方格,都需要重新计算一个地图的最大面积,所以 整体时间复杂度为: n 4 n^4 n4,没有进行任何优化显然不是一个比较好的选择。

其实每次深搜遍历计算最大岛屿面积,我们都做了很多重复的工作。

只要用一次深搜把每个岛屿的面积记录下来就好。

  • 第一步:一次遍历地图,得出各个岛屿的面积,并做编号记录。可以使用map记录,key为岛屿编号,value为岛屿面积
  • 第二步:遍历地图,遍历0的方格(因为要将0变成1),并统计该1(由0变成的1)周边岛屿面积,将其相邻面积相加在一起,遍历所有 0 之后,就可以得出 选一个0变成1 之后的最大面积。

下面的代码均适用于grid的长宽不等的情形!

代码实现1:

class Solution {
private:
    int count;
    int dir[4][2] = {0, 1, 1, 0, -1, 0, 0, -1}; // 四个方向
    void dfs(vector<vector<int>>& grid, vector<vector<bool>>& visited, int x, int y, int mark) {
        if (visited[x][y] || grid[x][y] == 0) return; // 终止条件:访问过的节点 或者 遇到海水
        visited[x][y] = true; // 标记访问过
        grid[x][y] = mark; // 给陆地标记新标签
        count++;
        for (int i = 0; i < 4; i++) {
            int nextx = x + dir[i][0];
            int nexty = y + dir[i][1];
            if (nextx < 0 || nextx >= grid.size() || nexty < 0 || nexty >= grid[0].size()) continue;  // 越界了,直接跳过
            dfs(grid, visited, nextx, nexty, mark);
        }
    }

public:
    int largestIsland(vector<vector<int>>& grid) {
        int n = grid.size(), m = grid[0].size();
        vector<vector<bool>> visited = vector<vector<bool>>(n, vector<bool>(m, false)); // 标记访问过的点
        unordered_map<int ,int> gridNum;
        int mark = 2; // 记录每个岛屿的编号
        bool isAllGrid = true; // 标记是否整个地图都是陆地
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (grid[i][j] == 0) isAllGrid = false;
                if (!visited[i][j] && grid[i][j] == 1) {
                    count = 0;
                    dfs(grid, visited, i, j, mark); // 将与其链接的陆地都标记上 true
                    gridNum[mark] = count; // 记录每一个岛屿的面积
                    mark++; // 记录下一个岛屿编号
                }
            }
        }
        if (isAllGrid) return n * m; // 如果都是陆地,返回全面积

        // 以下逻辑是根据添加陆地的位置,计算周边岛屿面积之和
        int result = 0; // 记录最后结果
        unordered_set<int> visitedGrid; // 标记访问过的岛屿
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                int count = 1; // 记录连接之后的岛屿数量
                visitedGrid.clear(); // 每次使用时,清空
                if (grid[i][j] == 0) {
                    for (int k = 0; k < 4; k++) {
                        int neari = i + dir[k][1]; // 计算相邻坐标
                        int nearj = j + dir[k][0];
                        if (neari < 0 || neari >= grid.size() || nearj < 0 || nearj >= grid[0].size()) continue;
                        if (visitedGrid.count(grid[neari][nearj])) continue; // 添加过的岛屿不要重复添加
                        // 把相邻四面的岛屿数量加起来
                        count += gridNum[grid[neari][nearj]];
                        visitedGrid.insert(grid[neari][nearj]); // 标记该岛屿已经添加过
                    }
                }
                result = max(result, count);
            }
        }
        return result;
    }
};
  • 时间复杂度:类似于上一题的分析为O(n * n)
  • 空间复杂度:O(n * n)

当然这里还有一个优化的点,就是 可以不用 visited数组,因为有mark来标记,所以遍历过的grid[i][j]是不等于1的。

代码实现2:

class Solution {
public:
    int dir[4][2] = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
    int count;
    void dfs(vector<vector<int>>& grid, int x, int y, int mark) {
        grid[x][y] = mark;
        count++;
        for (int i = 0; i < 4; ++i) {
            int nextx = x + dir[i][0];
            int nexty = y + dir[i][1];
            if (nextx < 0 || nextx >= grid.size() || nexty < 0 || nexty >= grid[0].size()) continue;
            if (grid[nextx][nexty] == 1) {
                dfs(grid, nextx, nexty, mark);
            }
        }
    }

    int largestIsland(vector<vector<int>>& grid) {
        int n = grid.size(), m = grid[0].size();
        bool isAllGrid = true;
        int mark = 2;
        unordered_map<int, int> gridNum;
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < m; ++j) {
                if (grid[i][j] == 0) isAllGrid = false;
                if (grid[i][j] == 1) {
                    count = 0;
                    dfs(grid, i, j, mark);
                    gridNum[mark] = count;
                    mark++;
                }
            }
        }

        if (isAllGrid) return n * m;

        int result = 0;
        unordered_set<int> visitedGrid;
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < m; ++j) {
                if (grid[i][j] == 0) {
                    count = 1;
                    visitedGrid.clear();
                    for (int k = 0; k < 4; ++k) {
                        int neari = i + dir[k][0];
                        int nearj = j + dir[k][1];
                        if (neari < 0 || neari >= n || nearj < 0 || nearj >= m) continue;
                        if (visitedGrid.count(grid[neari][nearj])) continue;
                        else {
                            count += gridNum[grid[neari][nearj]];
                            visitedGrid.insert(grid[neari][nearj]);
                        }
                    }
                    result = max(result, count);
                }
            }
        }
        return result;
    }
};

127 单词接龙(medium)

字典 wordList 中从单词 beginWord 和 endWord 的 转换序列 是一个按下述规格形成的序列 beginWord -> s1 -> s2 -> … -> sk:

  • 每一对相邻的单词只差一个字母。
  • 对于 1 <= i <= k 时,每个 si 都在 wordList 中。注意, beginWord 不需要在 wordList 中。
  • sk == endWord

给你两个单词 beginWord 和 endWord 和一个字典 wordList ,返回 从 beginWord 到 endWord 的 最短转换序列 中的 单词数目 。如果不存在这样的转换序列,返回 0 。

思路:因为我们要求最短转换序列,所以使用广搜,这里仅介绍最朴素的广搜,关于双向BFS(就是从头尾两端进行搜索)的优化不做详细讲解。

用队列来实现广度优先搜索,那么我们首先初始化队列然后从beginWord开始进行搜索,搜索空间为遍历当前搜索的word的每一个字母然后穷尽26个字母的组合,也就是m * 26。

// 初始化队列
queue<string> que;
que.push(beginWord);

while(!que.empty()) {
    string word = que.front();
    que.pop();
    for (int i = 0; i < word.size(); i++) {
        string newWord = word; // 用一个新单词替换word,因为每次置换一个字母
        for (int j = 0 ; j < 26; j++) {
            newWord[i] = j + 'a';
            //处理逻辑(包含了向que中插入可行的单词)
            }
        }
    }
}

但是搜索空间中的newWord只有在wordList中出现过我们才是有可能的选择,因为要不断对wordList进行搜索,所以在最开始我们将wordList转化为wordSet。有了wordSet我们可以先进行endWord是都否在词典中的检测。

unordered_set<string> wordSet(wordList.begin(), wordList.end());
// 如果endWord没有在wordSet出现,直接返回0
if (wordSet.find(endWord) == wordSet.end()) return 0;

同时我们要设置截止到每个可行单词的path的长度,这个可以用map来实现。

unordered_map<string, int> visitMap; // <word, 查询到这个word路径长度>
visitMap.insert(pair<string, int>(beginWord, 1));

有了上面这些准备,我们就可以书写循环中的处理逻辑这一部分了,注意在处理逻辑里面需要用标记位,标记着节点是否走过。
比如:如果我们搜索过A->B, 那么我们就将B放入visitMap,下次就不会出现A->B->C的情形了(这种情形既不可能是最短路径而且可能陷入死循环)
则处理逻辑的代码实现:

while(!que.empty()) {
    string word = que.front();
    que.pop();
    int path = visitMap[word]; // 这个word的路径长度
    for (int i = 0; i < word.size(); i++) {
        string newWord = word; // 用一个新单词替换word,因为每次置换一个字母
        for (int j = 0 ; j < 26; j++) {
            newWord[i] = j + 'a';
            if (newWord == endWord) return path + 1; // 找到了end,返回path+1
            // wordSet出现了newWord,并且newWord没有被访问过
            if (wordSet.find(newWord) != wordSet.end()
                    && visitMap.find(newWord) == visitMap.end()) {
                // 添加访问信息
                visitMap.insert(pair<string, int>(newWord, path + 1));
                que.push(newWord);
            }
        }
    }

注意事项:

  • 本题是一个无向图,需要用标记位,标记着节点是否走过,否则就会死循环!
  • 本题给出集合是数组型的,可以转成set结构,查找更快一些

代码实现:

class Solution {
public:
    int ladderLength(string beginWord, string endWord, vector<string>& wordList) {
        // 将vector转成unordered_set,提高查询速度
        unordered_set<string> wordSet(wordList.begin(), wordList.end());
        // 如果endWord没有在wordSet出现,直接返回0
        if (wordSet.find(endWord) == wordSet.end()) return 0;
        // 记录word是否访问过
        unordered_map<string, int> visitMap; // <word, 查询到这个word路径长度>
        // 初始化队列
        queue<string> que;
        que.push(beginWord);
        // 初始化visitMap
        visitMap.insert(pair<string, int>(beginWord, 1));

        while(!que.empty()) {
            string word = que.front();
            que.pop();
            int path = visitMap[word]; // 这个word的路径长度
            for (int i = 0; i < word.size(); i++) {
                string newWord = word; // 用一个新单词替换word,因为每次置换一个字母
                for (int j = 0 ; j < 26; j++) {
                    newWord[i] = j + 'a';
                    if (newWord == endWord) return path + 1; // 找到了end,返回path+1
                    // wordSet出现了newWord,并且newWord没有被访问过
                    if (wordSet.find(newWord) != wordSet.end()
                            && visitMap.find(newWord) == visitMap.end()) {
                        // 添加访问信息
                        visitMap.insert(pair<string, int>(newWord, path + 1));
                        que.push(newWord);
                    }
                }
            }
        }
        return 0;
    }
};

841 钥匙和房间(medium)

有 n 个房间,房间按从 0 到 n - 1 编号。最初,除 0 号房间外的其余所有房间都被锁住。你的目标是进入所有的房间。然而,你不能在没有获得钥匙的时候进入锁住的房间。

当你进入一个房间,你可能会在里面找到一套不同的钥匙,每把钥匙上都有对应的房间号,即表示钥匙可以打开的房间。你可以拿上所有钥匙去解锁其他房间。

给你一个数组 rooms 其中 rooms[i] 是你进入 i 号房间可以获得的钥匙集合。如果能进入 所有 房间返回 true,否则返回 false。

思路:整理时候的漏网之鱼,这个还是深搜广搜的模板题,可以回去图论1再回顾一下模板

代码实现1(深搜):

// 写法一:处理当前访问的节点
class Solution {
private:
    void dfs(const vector<vector<int>>& rooms, int key, vector<bool>& visited) {
        if (visited[key]) {
            return;
        }
        visited[key] = true;
        vector<int> keys = rooms[key];
        for (int key : keys) {
            // 深度优先搜索遍历
            dfs(rooms, key, visited);
        }
    }
public:
    bool canVisitAllRooms(vector<vector<int>>& rooms) {
        vector<bool> visited(rooms.size(), false);
        dfs(rooms, 0, visited);
        //检查是否都访问到了
        for (int i : visited) {
            if (i == false) return false;
        }
        return true;
    }
};

代码实现2(深搜):

写法二:处理下一个要访问的节点
class Solution {
private:  
    void dfs(const vector<vector<int>>& rooms, int key, vector<bool>& visited) {
        vector<int> keys = rooms[key];
        for (int key : keys) { 
            if (visited[key] == false) {
                visited[key] = true;
                dfs(rooms, key, visited);
            }       
        }
    }
public:
    bool canVisitAllRooms(vector<vector<int>>& rooms) {
        vector<bool> visited(rooms.size(), false); 
        visited[0] = true; // 0 节点是出发节点,一定被访问过
        dfs(rooms, 0, visited);  
        //检查是否都访问到了
        for (int i : visited) {
            if (i == false) return false;
        }
        return true;
    }
};

代码实现3(广搜):

class Solution {
bool bfs(const vector<vector<int>>& rooms) {
    vector<int> visited(rooms.size(), 0); // 标记房间是否被访问过
    visited[0] = 1; //  0 号房间开始
    queue<int> que;
    que.push(0); //  0 号房间开始

    // 广度优先搜索的过程
    while (!que.empty()) {
        int key = que.front(); que.pop();
         vector<int> keys = rooms[key];
         for (int key : keys) {
             if (!visited[key]) {
                 que.push(key);
                 visited[key] = 1;
             }
         }
    }
    // 检查房间是不是都遍历过了
    for (int i : visited) {
        if (i == 0) return false;
    }
    return true;

}
public:
    bool canVisitAllRooms(vector<vector<int>>& rooms) {
        return bfs(rooms);
    }
};

463 岛屿的周长(easy)

给定一个 row x col 的二维网格地图 grid ,其中:grid[i][j] = 1 表示陆地, grid[i][j] = 0 表示水域。

网格中的格子 水平和垂直 方向相连(对角线方向不相连)。整个网格被水完全包围,但其中恰好有一个岛屿(或者说,一个或多个表示陆地的格子相连组成的岛屿)。

岛屿中没有“湖”(“湖” 指水域在岛屿内部且不和岛屿周围的水相连)。格子是边长为 1 的正方形。网格为长方形,且宽度和高度均不超过 100 。计算这个岛屿的周长。

思路:这道题出现在这里只是因为要破除一下思路上的误区。岛屿问题最容易让人想到BFS或者DFS,但是这道题还真的没有必要,别把简单问题搞复杂了。

解法1:遍历每一个空格,遇到岛屿,计算其上下左右的情况,遇到水域或者出界的情况,就可以计算边了。

解法2:计算出总的岛屿数量,因为有一对相邻两个陆地,边的总数就减2,那么再计算出相邻岛屿的数量就可以了。result = 岛屿数量 * 4 - cover * 2

代码实现1:

class Solution {
public:
    int direction[4][2] = {0, 1, 1, 0, -1, 0, 0, -1};
    int islandPerimeter(vector<vector<int>>& grid) {
        int result = 0;
        for (int i = 0; i < grid.size(); i++) {
            for (int j = 0; j < grid[0].size(); j++) {
                if (grid[i][j] == 1) {
                    for (int k = 0; k < 4; k++) {       // 上下左右四个方向
                        int x = i + direction[k][0];
                        int y = j + direction[k][1];    // 计算周边坐标x,y
                        if (x < 0                       // i在边界上
                                || x >= grid.size()     // i在边界上
                                || y < 0                // j在边界上
                                || y >= grid[0].size()  // j在边界上
                                || grid[x][y] == 0) {   // x,y位置是水域
                            result++;
                        }
                    }
                }
            }
        }
        return result;
    }
};

代码实现2:

class Solution {
public:
    int islandPerimeter(vector<vector<int>>& grid) {
        int sum = 0;    // 陆地数量
        int cover = 0;  // 相邻数量
        for (int i = 0; i < grid.size(); i++) {
            for (int j = 0; j < grid[0].size(); j++) {
                if (grid[i][j] == 1) {
                    sum++;
                    // 统计上边相邻陆地
                    if(i - 1 >= 0 && grid[i - 1][j] == 1) cover++;
                    // 统计左边相邻陆地
                    if(j - 1 >= 0 && grid[i][j - 1] == 1) cover++;
                    // 为什么没统计下边和右边? 因为避免重复计算
                }
            }
        }
        return sum * 4 - cover * 2;
    }
};

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

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

相关文章

Kafka入门介绍+集群部署+简单使用

Kafka入门介绍集群部署简单使用 简介核心概念Broker&#xff08;服务节点/实例&#xff09;Producer&#xff08;生产者&#xff09;Topic&#xff08;主题&#xff09;Partition&#xff08;分区&#xff09;Consumer&#xff08;消费者&#xff09;和Consumer Group&#xff…

Java 笔记 03:Java 基础知识,使用 IDEA 创建 Java 项目、设置注释颜色,以及自动生成 JavaDoc

一、前言 记录时间 [2024-04-21] 系列文章简摘&#xff1a; Java 笔记 01&#xff1a;Java 概述&#xff0c;MarkDown 常用语法整理 Java 笔记 02&#xff1a;Java 开发环境的搭建&#xff0c;IDEA / Notepad / JDK 安装及环境配置&#xff0c;编写第一个 Java 程序 本文讲述了…

中国人的谦逊与生俱来

中国人的谦逊是与生俱来的&#xff0c;我们从老子的《道德经》就能探知一二&#xff1a; 一、不自夸、不自傲 《道德经》原文&#xff1a;自见者不明&#xff1b;自是者不彰&#xff1b;自伐者无功&#xff1b;自矜者不长。&#xff08;第二十四章&#xff09; 译文&#xff…

【深度学习】写实转漫画——CycleGAN原理解析

1、前言 上一篇&#xff0c;我们讲解了按照指定文本标签生成对应图像的CGAN。本篇文章&#xff0c;我们讲CycleGAN。这个模型可以对图像风格进行转化&#xff0c;并且训练还是在非配对的训练集上面进行的&#xff0c;实用性挺大 原论文&#xff1a;Unpaired Image-to-Image T…

Matlab|含sop的配电网重构(含风光|可多时段拓展)

目录 1 主要内容 2 部分程序 3 下载链接 1 主要内容 之前分享了很多配电网重构的程序&#xff0c;每个程序针对场景限定性比较大&#xff0c;程序初学者修改起来难度较大&#xff0c;本次分享一个基础程序&#xff0c;针对含sop的配电网重构模型&#xff0c;含风电和光伏&am…

FPGA - 基于自定义AXI FULL总线的PS和PL交互

前言 在FPGA - ZYNQ 基于Axi_Lite的PS和PL交互中&#xff0c;介绍了基于基于AXi_Lite的PL和PS交互&#xff0c;接下来构建基于基于Axi_Lite的PS和PL交互。 AXI_GP、AXI_HP和AXI_ACP接口 首先看一下ZYNQ SoC的系统框图&#xff0c;如下图所示。在图中&#xff0c;箭头方向代表…

【LeetCode】100、相同的树

100、相同的树 文章目录 一、DFS1.1 DFS 二、多语言解法 一、DFS 因为判断【相同的树】&#xff0c;是一个公用的子问题&#xff0c;所以可以递归判断节点的左、右孩子。 1.1 DFS func isSameTree(p *TreeNode, q *TreeNode) bool {if p nil && q nil {return tru…

2024蓝桥杯嵌入式模板代码详解

文章目录 一、STM32CubeMx配置二、LED模板代码三、LCD模板代码 一、STM32CubeMx配置 打开STM32CubeMx&#xff0c;选择【File】->【New Project】&#xff0c;进入芯片选择界面&#xff0c;搜索到蓝桥杯官方的芯片型号&#xff0c;并点击收藏&#xff0c;下次直接点击收藏就…

【C++提高】常用容器

常用容器 引言&#xff1a;迭代器的使用一、vector容器1. vector基本概念2. vector的迭代器3. vector构造函数4. vector赋值操作5. vector容量和大小6. vector插入和删除7. vector数据存取8. vector互换容器9. vector预留空间 二、deque容器1. deque容器的基本概念2. deque容器…

leetcode:438. 找到字符串中所有字母异位词

给定两个字符串 s 和 p&#xff0c;找到 s 中所有 p 的 异位词 的子串&#xff0c;返回这些子串的起始索引。不考虑答案输出的顺序。 异位词 指由相同字母重排列形成的字符串&#xff08;包括相同的字符串&#xff09;。 示例 1: 输入: s "cbaebabacd", p "…

强固型工业电脑在仓储智能化行业、RFID+叉车电脑、扫码枪+叉车电脑应用

仓储智能化行业应用 科技的使命&#xff0c;是为了智能物流行业的客户&#xff0c;提供最佳的工业电脑解决方案。为了提高在仓库或者物流配送中心工作的效率&#xff0c;我们对仓储的不同应用需要&#xff0c;设计了一系列工业电脑来满足客户的需求。其中包括专业的叉车车载电…

NetSuite Connector实践分享

A.I 成为我们在企业信息化应用领域的研究重点。A&#xff0c;即是人工智能&#xff1b;I&#xff0c;即是集成技术。 在早前的一期我们谈了人工智能在模糊信息处理方面的应用。 NetSuite 文心一言&#xff08;Ernie&#xff09;的AI应用-CSDN博客 今朝&#xff0c;我们谈一下…

【JavaScript编程实操14】DOM实操_回到顶部

前言 本次主要是针对Javascript阶段的DOM实操方面的练习&#xff0c;本次主要实现当页面内容过多时&#xff0c;可以点击按钮&#xff0c;快速回到页面顶部的效果。这次的实现逻辑比较简单&#xff0c;主要是应用函数实现页面的回到顶部功能&#xff0c;this.scrollTo(0, 0)可以…

vue element ui 打开弹窗出现黑框问题

文章目录 问题描述解决方案 问题描述 大家好&#xff01;今天是2024年4月20日 | 农历三月十二&#xff0c;周六的我又做在公司里面写起了代码 今天在做项目的时候遇到一个奇怪的问题&#xff0c;如下图所示&#xff1a; 因为这个页面我做了两个弹框&#xff0c;先弹出来第一个弹…

【归并】Leetcode 排序数组

题目讲解 912. 排序数组 算法讲解 使用归并算法排序数组&#xff0c;我们先在数组中寻找一个mid点&#xff0c;然后把数组分成了两部分&#xff0c;我们先排左部分&#xff0c;排左边部分的时候有需要将当前的子数组分成两部分&#xff0c;继续循环&#xff0c;直到当前子数组…

Spec-Gaussian:3D高斯溅射的各向异性视图相关外观

Spec-Gaussian: Anisotropic View-Dependent Appearance for 3D Gaussian Splatting Spec-Gaussian&#xff1a;3D高斯溅射的各向异性视图相关外观 Ziyi Yang1,3  Xinyu Gao1  Yangtian Sun2  Yihua Huang2  Xiaoyang Lyu2 杨子怡 1,3 高新宇 1 太阳扬天 2 黄宜华 2 吕晓阳…

驱动开发-windows驱动设计目标

驱动程序和应用程序不一样的&#xff0c;由于其直接运行于windows r0级&#xff0c;故对于开发有更多和更严格的标准&#xff0c;一般会有以下一些常见的设计目标: 安全性、可移植性、可配置性、 可被中断、多处理器安全、可重用 IRP、 支持异步 I/O这些是基本目标。 1. 安全…

C++语言·类和对象(下)

1. 初始化列表 我们回忆上节写的MyQueue类&#xff0c;其中有两个栈类和一个int类型&#xff0c;栈类因为其特殊性&#xff0c;要开空间&#xff0c;所以我们必须手搓Stack类的构造函数。但是正常来说MyQueue自动生成的构造函数会调用自定义类型的默认构造函数&#xff0c;也就…

C语言 | Leetcode C语言题解之第41题缺失的第一个正数

题目&#xff1a; 题解&#xff1a; int firstMissingPositive(int* nums, int numsSize) {for (int i 0; i < numsSize; i) {while (nums[i] > 0 && nums[i] < numsSize &&nums[nums[i] - 1] ! nums[i]) {int t nums[nums[i] - 1];nums[nums[i] -…