LeetCode 778. Swim in Rising Water【最小瓶颈路;二分+BFS或DFS;计数排序+并查集;最小生成树】2096

news2024/10/7 16:17:59

本文属于「征服LeetCode」系列文章之一,这一系列正式开始于2021/08/12。由于LeetCode上部分题目有锁,本系列将至少持续到刷完所有无锁题之日为止;由于LeetCode还在不断地创建新题,本系列的终止日期可能是永远。在这一系列刷题文章中,我不仅会讲解多种解题思路及其优化,还会用多种编程语言实现题解,涉及到通用解法时更将归纳总结出相应的算法模板。

为了方便在PC上运行调试、分享代码文件,我还建立了相关的仓库:https://github.com/memcpy0/LeetCode-Conquest。在这一仓库中,你不仅可以看到LeetCode原题链接、题解代码、题解文章链接、同类题目归纳、通用解法总结等,还可以看到原题出现频率和相关企业等重要信息。如果有其他优选题解,还可以一同分享给他人。

由于本系列文章的内容随时可能发生更新变动,欢迎关注和收藏征服LeetCode系列文章目录一文以作备忘。

在一个 n x n 的整数矩阵 grid 中,每一个方格的值 grid[i][j] 表示位置 (i, j) 的平台高度。

当开始下雨时,在时间为 t 时,水池中的水位为 t 。你可以从一个平台游向四周相邻的任意一个平台,但是前提是此时水位必须同时淹没这两个平台。假定你可以瞬间移动无限距离,也就是默认在方格内部游动是不耗时的。当然,在你游泳的时候你必须待在坐标方格里面。

你从坐标方格的左上平台 (0,0) 出发。返回 你到达坐标方格的右下平台 (n-1, n-1) 所需的最少时间 。

示例 1:

输入: grid = [[0,2],[1,3]]
输出: 3
解释:
时间为0时,你位于坐标方格的位置为 `(0, 0)。`
此时你不能游向任意方向,因为四个相邻方向平台的高度都大于当前时间为 0 时的水位。
等时间到达 3 时,你才可以游向平台 (1, 1). 因为此时的水位是 3,坐标方格中的平台没有比水位 3 更高的,所以你可以游向坐标方格中的任意位置

示例 2:

输入: grid = [[0,1,2,3,4],[24,23,22,21,5],[12,13,14,15,16],[11,17,18,19,20],[10,9,8,7,6]]
输出: 16
解释: 最终的路线用加粗进行了标记。
我们必须等到时间为 16,此时才能保证平台 (0, 0)(4, 4) 是连通的

提示:

  • n == grid.length
  • n == grid[i].length
  • 1 <= n <= 50
  • 0 <= grid[i][j] < n^2
  • grid[i][j] 中每个值 均无重复

注意题目中的重要信息:假定你可以 瞬间移动 无限距离,游动不耗时。当前这个问题就转换成为:找一个时刻 t t t ,使得这个二维网格上数值 小于等于 t t t 的部分,存在一条从左上角到右下角的路径。即:经过了时间 t t t 以后,可以瞬间从左上角(坐标 [ 0 , 0 ] [0, 0] [0,0] )游到右下角(坐标 [ N − 1 , N − 1 ] [N - 1, N - 1] [N1,N1] )。

相似题目:

  • LeetCode 2812. Find the Safest Path in a Grid
  • LeetCode 1631. 最小体力消耗路径

解法1 二分+BFS/DFS

这种做法是LeetCode 2812. Find the Safest Path in a Grid的完全简化版、在2812中需要先进行一次多源BFS、再来二分答案,也用在LeetCode 1631. 最小体力消耗路径中。

根据题目中的描述,给定了 g r i d [ i ] [ j ] grid[i][j] grid[i][j] 的范围是 [ 0 , n 2 − 1 ] [0, n^2 - 1] [0,n21] ,所以答案必然落在此范围:

  • 如果等待的时间 t t t 越少,网格上可以游泳的部分就越少,存在从左上角到右下角的一条路径的可能性越小
  • 如果等待的时间 t t t 越多,网格上可以游泳的部分就越多,存在从左上角到右下角的一条路径的可能性越大。


这是本问题具有的 单调性 。因此可以使用二分查找定位到最短等待时间。

假设最优解为 l l l 的话(恰好能到达右下角的时间),那么小于 l l l 的时间无法到达右下角,大于 l l l 的时间能到达右下角,因此在以最优解 l l l 为分割点的数轴上具有二段性,可以通过「二分」找到分割点 l l l

注意:「二分」的本质是两段性,并非单调性。只要一段满足某个性质,另外一段不满足某个性质,就可以用「二分」。其中 33. 搜索旋转排序数组 是一个很好的说明例子。

具体来说:在区间 [ 0 , N ∗ N − 1 ] [0, N * N - 1] [0,NN1] 里猜一个整数,针对这个整数从起点(左上角)开始做一次DFS或BFS:

  • 当小于等于该数值时,如果存在一条从左上角到右下角的路径,说明答案可能是这个数值,也可能更小
  • 当小于等于该数值时,如果不存在一条从左上角到右下角的路径,说明答案一定比这个数值更大。
  • 按照这种方式不断缩小搜索的区间,最终找到最少等待时间。
class Solution {
public:
    int swimInWater(vector<vector<int>>& grid) {
        int n = grid.size();
        typedef pair<int, int> pii;
        int d[4][2] = {-1, 0, 1, 0, 0, -1, 0, 1};
        auto check = [&](int lim) { // 能否在<=lim时间从左上到右小
            bool vis[n][n]; memset(vis, false, sizeof(vis));
            queue<pii> q;
            if (grid[0][0] <= lim) {
                q.push(pii(0, 0)); vis[0][0] = true;
            }
            while (!q.empty()) {
                pii p = q.front(); q.pop();
                int i = p.first, j = p.second;
                if (i == n - 1 && j == n - 1) return true;
                for (int k = 0; k < 4; ++k) {
                    int x = i + d[k][0], y = j + d[k][1];
                    if (x < 0 || x >= n || y < 0 || y >= n || grid[x][y] > lim || vis[x][y])
                        continue;
                    q.push(pii(x, y));
                    vis[x][y] = true;
                }
            }
            return vis[n - 1][n - 1];
        };
        int l = grid[0][0], r = n * n;
        while (l < r) {
            int mid = (l + r) >> 1;
            if (check(mid)) r = mid;
            else l = mid + 1;
        }
        return l;
    }
};

复杂度分析:

  • 时间复杂度: O ( N 2 log ⁡ N ) O(N^2 \log N) O(N2logN) 。 其中 N N N 是方格的边长。最差情况下进行 log ⁡ N 2 \log N^2 logN2 次二分查找,每一次二分查找最差情况下要遍历所有单元格一次,时间复杂度为 O ( N 2 ) O(N^2) O(N2) 。总的时间复杂度为 O ( N 2 log ⁡ N 2 ) = O ( 2 N 2 log ⁡ N ) = O ( N 2 log ⁡ N ) O(N^2 \log N^2) = O(2N^2 \log N) = O(N^2 \log N) O(N2logN2)=O(2N2logN)=O(N2logN)
  • 空间复杂度: O ( N 2 ) O(N^2) O(N2) 。 数组 v i s vis vis 的大小为 N 2 N^2 N2 ,如果使用深度优先遍历,须要使用的栈的大小最多为 N 2 N^2 N2 ,如果使用广度优先遍历,须要使用的队列的大小最多为 N 2 N^2 N2

解法2 计数排序+并查集

关于连通性的问题,如果只问结果,不问具体怎么连起来的,还可以考虑使用并查集。由于题目要找的是最少等待时间,可以模拟下雨的过程,把网格抽象成一个无权图,每经过一个时刻,水位不断提高,就考虑此时和雨水高度相等的单元格,考虑这个单元格的上、下、左、右、四个方向且高度更低的单元格,把它们在并查集中进行合并

为了找到高度相近的单元格,需要先进行计数排序。注意 grid[i][j] 中每个值 均无重复

class Solution {
    private class UnionFind {
        private int[] parent;
        public UnionFind(int n) {
            parent = new int[n];
            for (int i = 0; i < n; ++i) parent[i] = i;
        }
        public int find(int x) {
            return x != parent[x] ? parent[x] = find(parent[x]) : x;
        }
        public boolean isConnected(int x, int y) { return find(x) == find(y); }
        public void union(int p, int q) {
            int rp = find(p), rq = find(q);
            if (rp == rq) return;
            parent[rp] = rq;
        }
    }
    public int swimInWater(int[][] grid) {
        int n = grid.length;
        int len = n * n;
        int[] heightToIndex = new int[len]; // 方格的高度:方格的坐标
        for (int i = 0; i < n; ++i) 
            for (int j = 0; j < n; ++j)
                heightToIndex[grid[i][j]] = i * n + j;

        int[][] d = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
        UnionFind unionFind = new UnionFind(len);
        for (int i = 0; i < len; ++i) { // 高度从低到高
            int x = heightToIndex[i] / n, y = heightToIndex[i] % n;
            for (int j = 0; j < 4; ++j) {
                int u = x + d[j][0], v = y + d[j][1];
                if (u >= 0 && u < n && v >= 0 && v < n && grid[u][v] <= i)
                    unionFind.union(heightToIndex[i], u * n + v); // 合并
            }
            if (unionFind.isConnected(0, len - 1)) return i; // 连通
        }
        return -1;
    }
}

这种做法部分类似LeetCode 2812. Find the Safest Path in a Grid的并查集做法——每轮将「到最近小偷的距离为 x x x 的单元格」与「距离为 x + 1 x+1 x+1 的单元格」合并。

复杂度分析:

  • 时间复杂度: O ( N 2 log ⁡ N ) O(N^2 \log N) O(N2logN) 。 其中 N N N 是方格的边长。计数排序 O ( N 2 ) O(N^2) O(N2) ,合并周围、检查起点和终点是否属于同个连通分量 O ( log ⁡ N 2 ) O(\log N^2) O(logN2) 。总的时间复杂度为 O ( N 2 + N 2 log ⁡ N 2 ) = O ( N 2 + 2 N 2 log ⁡ N ) = O ( N 2 log ⁡ N ) O(N^2+ N^2 \log N^2) = O(N^2 + 2N^2 \log N) = O(N^2 \log N) O(N2+N2logN2)=O(N2+2N2logN)=O(N2logN)
  • 空间复杂度: O ( N 2 ) O(N^2) O(N2) 。 数组 index 的大小为 N 2 N^2 N2 ,并查集底层的长度均为 N 2 N^2 N2

解法3 最小瓶颈路模型+最小生成树(Prim+堆/Kruskal+边集数组)

根据题意,我们要找的是从左上角到右下角的最优路径,其中最优路径是指途径的边的最大权重值最小,然后输出最优路径中的最大权重值。

无向图 G G G x x x y y y最小瓶颈路是这样的一类简单路径,满足这条路径上的最大边权在所有 x x x y y y 的简单路径中是最小的。
根据最小生成树定义, x x x y y y 的最小瓶颈路上的最大边权等于最小生成树上 x x x y y y 路径上的最大边权。虽然最小生成树不唯一,但是每种最小生成树 x x x y y y 路径的最大边权相同且为最小值。也就是说,每种最小生成树上的 x x x y y y 的路径均为最小瓶颈路。

这道题和第 1631 题,虽然物理问题不同,但是背后的数学模型几乎完全相同,唯一的区别在于第 1631 题将相邻格子的高度差作为边的权重、而本题将相邻两格子间高度的最大值作为边的权重。在看清楚物理问题背后的数学模型后,这两道题的物理问题都会迎刃而解。

和1631. 最小体力消耗路径几乎是完全一样的思路。我们不必实际求出整个最小生成树,只需要求出最小生成树上 x x x y y y 路径上的最大边权

根据最小瓶颈路模型,我们可以使用Kruskal最小生成树算法:

  1. 先遍历所有的点,将所有的边加入集合,存储的格式为数组 [ a , b , w ] [a, b, w] [a,b,w] ,代表编号为 a a a 的点和编号为 b b b 的点之间的权重为 w w w(按照题意, w w w 为两者的最大高度)。
  2. 对边集集合进行排序,按照 w w w 进行从小到达排序
  3. 当我们有了所有排好序的候选边集合之后,对边从前往后处理,选择那些不会出现环的边加入最小生成树中。
  4. 每次加入一条边之后,使用并查集来查询左上角点和右下角点是否连通。如果连通,那么该边的权重即是答案
class Solution {
    private class UnionFind {
        private int[] parent;
        public UnionFind(int n) {
            parent = new int[n];
            for (int i = 0; i < n; ++i) parent[i] = i;
        }
        public int find(int x) {
            return x != parent[x] ? parent[x] = find(parent[x]) : x;
        }
        public boolean isConnected(int x, int y) { return find(x) == find(y); }
        public void union(int p, int q) {
            int rp = find(p), rq = find(q);
            if (rp == rq) return;
            parent[rp] = rq;
        }
    }
    public int swimInWater(int[][] grid) {
        int n = grid.length;
        int len = n * n;
        int[][] d = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
        UnionFind unionFind = new UnionFind(len);

        // 预处理所有无向边
        // edge存[a,b,w]: 代表从a到b所需的时间点为w
        // 虽然我们可以往四个方向移动,但只要对于每个点都添加「向右」和「向下」
        // 两条边的话,其实就已经覆盖了所有边
        List<int[]> edges = new ArrayList<>();
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < n; ++j) {
                int index = i * n + j;
                int a, b, w;
                if (i + 1 < n) {
                    a = index; b = (i + 1) * n + j;
                    w = Math.max(grid[i][j], grid[i + 1][j]);
                    edges.add(new int[]{a, b, w});
                }
                if (j + 1 < n) {
                    a = index; b = i * n + (j + 1);
                    w = Math.max(grid[i][j], grid[i][j + 1]);
                    edges.add(new int[]{a, b, w});
                }   
            }
        }
        Collections.sort(edges, (a, b) -> a[2] - b[2]); // 根据w权值升序
        // 从「小边」开始添加,当某一条边应用之后,恰好使得「起点」和「结点」联通
        // 那么代表找到了「最短路径」中的「权重最大的边」
        int start = 0, end = len - 1;
        for (int[] edge : edges) {
            int a = edge[0], b = edge[1], w = edge[2];
            unionFind.union(a, b);
            if (unionFind.isConnected(start, end)) return w;
        }
        return 0;
    }
}

Kruskal虽然没有求出完整最小生成树,但是对所有边进行了排序。我们可以使用Prim算法+优先队列。

下面将此问题抽象为一张带权有向图,每个单元格为顶点,有指向相邻顶点的有向边,边的权值为指向顶点的高度(水位到达该顶点的高度才可游到该顶点)。然后用Prim算法,求出最小生成树上左上角的点到右下角的点的路径上的最大边权。此时不用对所有边进行排序。
500
Prim算法在示例2的用法如下:

class Solution {
    public int swimInWater(int[][] grid) {
        int n = grid.length;
        Queue<int[]> minHeap = new PriorityQueue<>(Comparator.comparingInt(o -> grid[o[0]][o[1]]));
        minHeap.offer(new int[]{0, 0});
        
        boolean[][] vis = new boolean[n][n];
        // dist[i][j]表示 到顶点[i,j] 要等待的最少时间
        int[][] dist = new int[n][n];
        for (int[] row : dist) Arrays.fill(row, n * n);
        dist[0][0] = grid[0][0];

        int[][] d = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
        while (!minHeap.isEmpty()) { // 找最短的边
            int[] front = minHeap.poll();
            int x = front[0], y = front[1];
            if (vis[x][y]) continue;
            vis[x][y] = true;
            if (x == n - 1 && y == n - 1) return dist[n - 1][n - 1];
            // 更新
            for (int i = 0; i < 4; ++i) {
                int u = x + d[i][0], v = y + d[i][1];
                if (u >= 0 && u < n && v >= 0 && v < n 
                    && !vis[u][v] && // prim算法
                    Math.max(dist[x][y], grid[u][v]) < dist[u][v]) {
                        dist[u][v] = Math.max(dist[x][y], grid[u][v]);
                        minHeap.offer(new int[]{u, v});
                    }
            }
        }
        return -1;
    }
}

复杂度分析:

  • 时间复杂度: O ( N 2 log ⁡ N ) O(N^2 \log N) O(N2logN) 。 使用了优先队列的 Prim 算法的时间复杂度是 O ( E log ⁡ E ) O(E \log E) O(ElogE) ,这里 E E E 是边数,至多是顶点数的 4 4 4 倍,顶点数为 N 2 N^2 N2 ,因此 O ( E log ⁡ E ) = O ( 4 N 2 log ⁡ N 2 ) = O ( N 2 log ⁡ N ) O(E \log E) = O(4N^2 \log N^2) = O(N^2 \log N) O(ElogE)=O(4N2logN2)=O(N2logN)
  • 空间复杂度: O ( N 2 ) O(N^2) O(N2) 。 数组 v i s vis vis d i s t dist dist 的大小为 O ( N 2 ) O(N^2) O(N2) ,优先队列中保存的边的总数也是 N 2 N^2 N2 级别的。

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

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

相关文章

城市最短路

题目描述 下图表示的是从城市A到城市H的交通图。从图中可以看出&#xff0c;从城市A到城市H要经过若干个城市。现要找出一条经过城市最少的一条路线。 输入输出格式 输入格式&#xff1a; 无 输出格式&#xff1a; 倒序输出经过城市最少的一条路线 输入输出样例 输入样例…

【LeetCode75】第二十七题(933)最近的请求次数

目录 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 代码运行结果&#xff1a; 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 首先这是LeetCode75里第一道设计类的题目&#xff0c;这种类型的题目会比较新颖&#xff0c;就是按照题目要求来设计一个类。然后…

GIL 锁或将在 CPython 中成为可选项

哈喽大家好&#xff0c;我是咸鱼 几天前有媒体报道称&#xff0c;经过多次辩论&#xff0c;Python 指导委员会打算批准通过 PEP 703 提案&#xff0c;让 GIL&#xff08;全局解释器&#xff09;锁在 CPython 中成为一个可选项 PEP 703 提案主要目标是使 GIL 变成可选项&#…

二叉树的讲解

&#x1f493;博主个人主页:不是笨小孩&#x1f440; ⏩专栏分类:数据结构与算法&#x1f440; 刷题专栏&#x1f440; C语言&#x1f440; &#x1f69a;代码仓库:笨小孩的代码库&#x1f440; ⏩社区&#xff1a;不是笨小孩&#x1f440; &#x1f339;欢迎大家三连关注&…

定义行业新标准?谷歌:折叠屏手机可承受20万次折叠

根据Patreon账户上的消息&#xff0c;Android专家Mishaal Rahman透露&#xff0c;谷歌计划推出新的硬件质量标准&#xff0c;以满足可折叠手机市场的需求。Android原始设备制造商&#xff08;OEM&#xff09;将需要完成谷歌提供的问卷调查&#xff0c;并提交样品设备进行严格审…

读书笔记 |【项目思维与管理】➾ 顺势而动

读书笔记 |【项目思维与管理】➾ 顺势而动 一、企业步入“终结者时代”二、过去成功的经验也许是最可怕的三、做好非重复性的事四、适应客户是出发点五、向知识型企业转变六、速度是决胜条件 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; …

【C++ 学习 ⑬】- 详解 list 容器

目录 一、list 容器的基本介绍 二、list 容器的成员函数 2.1 - 迭代器 2.2 - 修改操作 三、list 的模拟实现 3.1 - list.h 3.2 - 详解 list 容器的迭代器 3.2 - test.cpp 一、list 容器的基本介绍 list 容器以类模板 list<T>&#xff08;T 为存储元素的类型&…

ruoyi-vue-v3.8.6-搭建

一、准备工作 环境&#xff1a; win10、MySQL8、JDKjdk1.8.0_311 redis6.2.6 IDEA 2022.3.3 maven3.9 Node v18.14.2 npm 9.5.0 版本&#xff1a; 若依框架官方文档&#xff1a;http://doc.ruoyi.vip/ 官网导航&#xff1a;http://120.79.202.7/ 若依项目地址&#xff…

将数组(矩阵)旋转根据指定的旋转角度scipy库的rotate方法

【小白从小学Python、C、Java】 【计算机等考500强证书考研】 【Python-数据分析】 将数组(矩阵)旋转 根据指定的旋转角度 scipy库的rotate方法 关于下列代码说法正确的是&#xff1f; import numpy as np from scipy.ndimage import rotate a np.array([[1,2,3,4], …

腾讯云服务器竞价实例是什么?适用于什么行业?有啥优惠?

腾讯云服务器CVM计费模式分为包年包月、按量计费和竞价实例&#xff0c;什么是竞价实例&#xff1f;竞价实例和按量付费相类似&#xff0c;优势是价格更划算&#xff0c;缺点是云服务器实例有被自动释放风险&#xff0c;腾讯云服务器网来详细说下什么是竞价实例&#xff1f;以及…

八、解析应用程序——分析应用程序(1)

文章目录 一、确定用户输入入口点1.1 URL文件路径1.2 请求参数1.3 HTTP消息头1.4 带外通道 二、确定服务端技术2.1 提取版本信息2.2 HTTP指纹识别2.3 文件拓展名2.4 目录名称2.5 会话令牌2.6 第三方代码组件 小结 枚举尽可能多的应用程序内容只是解析过程的一个方面。分析应用程…

Leetcode35 搜索插入位置

给定一个排序数组和一个目标值&#xff0c;在数组中找到目标值&#xff0c;并返回其索引。如果目标值不存在于数组中&#xff0c;返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 解析&#xff1a;以示例2来举例&#xff0c;left 0,right 3,mid 1…

【CSS】CSS 布局——弹性盒子

Flexbox 是一种强大的布局系统&#xff0c;旨在更轻松地使用 CSS 创建复杂的布局。 它特别适用于构建响应式设计和在容器内分配空间&#xff0c;即使项目的大小是未知的或动态的。Flexbox 通常用于将元素排列成一行或一列&#xff0c;并提供一组属性来控制 flex 容器内的项目行…

SpringMVC的异常处理机制

1、简介 系统中异常包括两类&#xff1a;预期异常和运行时异常RuntimeException&#xff0c;前者通过捕获异常从而获取异常信息&#xff0c;后 者主要通过规范代码开发、测试等手段减少运行时异常的发生。 系统的Dao、Service、Controller出现都通过throws Exception向上抛出…

BFS 五香豆腐

题目描述 经过谢老师n次的教导&#xff0c;dfc终于觉悟了——过于腐败是不对的。但是dfc自身却无法改变自己&#xff0c;于是他找到了你&#xff0c;请求你的帮助。 dfc的内心可以看成是5*5个分区组成&#xff0c;每个分区都可以决定的的去向&#xff0c;0表示继续爱好腐败&…

【图像分类】CNN + Transformer 结合系列.4

介绍两篇利用Transformer做图像分类的论文&#xff1a;CoAtNet&#xff08;NeurIPS2021&#xff09;&#xff0c;ConvMixer&#xff08;ICLR2022&#xff09;。CoAtNet结合CNN和Transformer的优点进行改进&#xff0c;ConvMixer则patch的角度来说明划分patch有助于分类。 CoAtN…

多目标优化算法之樽海鞘算法(MSSA)

樽海鞘算法的主要灵感是樽海鞘在海洋中航行和觅食时的群聚行为。相关文献表示&#xff0c;多目标优化之樽海鞘算法的结果表明&#xff0c;该算法可以逼近帕雷托最优解&#xff0c;收敛性和覆盖率高。 通过给SSA算法配备一个食物来源库来解决第一个问题。该存储库维护了到目前为…

el-select 动态添加多个下拉框

实现的效果如下: 主要的代码如下: 这是formdata 的结构 主要的逻辑 在这个 methods

ubuntu supervisor 部署 python 项目

ubuntu supervisor 查看系统是否可用 cuda 初环境与设备安装 supervisor 环境创建 Supervisor 配置文件启动 Supervisor 服务管理项目 本篇文章将介绍 ubuntu supervisor 部署 python 项目 Supervisor 是一个用于管理和监控进程的系统工具。它的主要功能是确保系统中的进程持续…

Stable Diffusion WebUI 从零基础到入门

本文主要介绍Stable Diffusion WebUI的实际操作方法&#xff0c;涵盖prompt推导、lora模型、vae模型和controlNet应用等内容&#xff0c;并给出了可操作的文生图、图生图实战示例。适合对Stable Diffusion感兴趣&#xff0c;但又对Stable Diffusion WebUI使用感到困惑的同学&am…