当前位置: 首页 > news >正文

2258. 逃离火灾 : 详解如何从「二分」到「分类讨论」(图解过程)

题目描述

这是 LeetCode 上的 「2258. 逃离火灾」 ,难度为 「困难」

Tag : 「多源 BFS」、「二分」、「预处理」

给你一个下标从 0 开始大小为 m x n 的二维整数数组 grid,它表示一个网格图。

每个格子为下面 个值之一:

  • 0 表示草地。
  • 1 表示着火的格子。
  • 2 表示一座墙,你跟火都不能通过这个格子。

一开始你在最左上角的格子 ,你想要到达最右下角的安全屋格子

每一分钟,你可以移动到相邻的草地格子。

每次你移动之后 ,着火的格子会扩散到所有不是墙的相邻格子。

请你返回你在初始位置可以停留的最多分钟数,且停留完这段时间后你还能安全到达安全屋。

如果无法实现,请你返回 。如果不管你在初始位置停留多久,你总是能到达安全屋,请你返回

注意,如果你到达安全屋后,火马上到了安全屋,这视为你能够安全到达安全屋。

如果两个格子有共同边,那么它们为相邻格子。

示例 1: alt

输入:grid = [[0,2,0,0,0,0,0],[0,0,0,2,2,1,0],[0,2,0,0,1,2,0],[0,0,2,2,2,0,2],[0,0,0,0,0,0,0]]

输出:3

解释:上图展示了你在初始位置停留 3 分钟后的情形。
你仍然可以安全到达安全屋。
停留超过 3 分钟会让你无法安全到达安全屋。

示例 2: alt

输入:grid = [[0,0,0,0],[0,1,2,0],[0,2,0,0]]

输出:-1

解释:上图展示了你马上开始朝安全屋移动的情形。
火会蔓延到你可以移动的所有格子,所以无法安全到达安全屋。
所以返回 -1 。

示例 3: alt

输入:grid = [[0,0,0],[2,2,0],[1,2,0]]

输出:1000000000

解释:上图展示了初始网格图。
注意,由于火被墙围了起来,所以无论如何你都能安全到达安全屋。
所以返回 109 。

提示:

  • grid[i][j]01 或者 2

二分 + BFS

火势蔓延是一个固定的过程,只有人员移动需要决策。

假设人员最晚在 秒后出发,仍能到达安全屋,说明人员对逃走路线的访问,要比火势更快。那么人员在更早的时间点( 秒后)出发,必然仍能按照原定路线到达安全屋(火势对路径的影响不变)。

因此,在以 为分割点的(正整数)数轴上,具有二段性,可运用「二分」求分割点。

假设存在某个判定函数 check,用于检查人员在 秒后出发能否到达安全屋,那么可知:

  • 当实际延迟出发的秒数,小于等于 秒,必然能安全到达
  • 当实际延迟出发的描述,超过 秒,必然不能安全到达

在人员移动路线中,“回头路”是没有意义的,因此人员对每个点的访问次数最多为一次。同时,不考虑墙的阻拦,火势也最多在不超过棋盘大小的时间内完全蔓延。

这指导我们最大延迟出发时间不会超过 ,可在 值域内进行二分。

接下来,考虑如何实现 check 函数,函数入参为延迟出发秒数 ,返回值为延迟出发后能否到达安全屋。

首先,对于普通位置,如果火势和人员同时到达,是不允许的,而安全屋 位置的同时到达,是允许的。

因此,我们需要使用两个二维数组 fgpg 分别记录「火势」和「人员」到达某个位置的最早时间。

  1. 创建用于模拟火势蔓延的队列 fire,遍历网格,将火源位置进行入队,更新火源位置 ,表示火势在第一秒时最早出现在此处;

  2. 运用 BFS,模拟 秒的火势蔓延,火势在这 秒内所蔓延到的新位置,均看作为起始火源,即有

    若执行完 秒后,火势已蔓延到人员起始位置 ,那么延迟 秒出发不可行,直接返回 False

  3. 创建用于模拟人员移动的队列 people,将起始位置 进行入队,更新

    运用 BFS,按照「先火后人」的方式,同步模拟「火势蔓延」和「人员移动」过程。普通位置,只要火势蔓延到,那么人将无法移动到此处;安全屋位置,需要判断是否与火势同一时刻到达。

为了方便,将「火势蔓延」和「人员移动」统一成 update 操作,入参包括当前队列 d,标识位 isFire,以及移动偏移量 offset

在进行 秒的火势蔓延时,调用 次的 update(fire, true, 0)。在火势和人员同步模拟时,分别调用 update(fire, true, 1)update(people, false, 1)

使用示例 来举个 🌰:

alt
alt

Java 代码:

class Solution {
    int[][] dirs = new int[][]{{0,1}, {0,-1}, {1,0}, {-1,0}};
    int n, m;
    boolean ok;
    int[][] g, fg, pg;
    public int maximumMinutes(int[][] grid) {
        g = grid;
        n = g.length; m = g[0].length;
        fg = new int[n][m]; pg = new int[n][m];
        if (!check(0)) return -1;
        int l = 0, r = n * m;
        while (l < r) {
            int mid = l + r + 1 >> 1;
            if (check(mid)) l = mid;
            else r = mid - 1;
        }
        return r == m * n ? (int)1e9 : r;
    }
    boolean check(int t) {
        ok = false;
        Deque<int[]> frie = new ArrayDeque<>();
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                fg[i][j] = pg[i][j] = 0;
                if (g[i][j] == 1) {
                    fg[i][j] = 1;
                    frie.addLast(new int[]{i, j});
                }
            }
        }
        while(t-- > 0) update(frie, true0);  // 先执行 t 秒的火势蔓延
        if (fg[0][0] != 0return false;
        Deque<int[]> people = new ArrayDeque<>();
        pg[0][0] = 1;
        people.addLast(new int[]{00});
        while (!people.isEmpty()) {
            // 先火后人, 同步进行
            update(frie, true1);
            update(people, false1);
            if (ok) return true;
        }
        return false;
    }
    void update(Deque<int[]> deque, boolean isFrie, int offset) {
        int sz = deque.size();
        while (sz-- > 0) {
            int[] info = deque.pollFirst();
            int x = info[0], y = info[1];
            for (int[] dir : dirs) {
                int nx = x + dir[0], ny = y + dir[1];
                if (nx < 0 || nx >= n || ny < 0 || ny >= m) continue;
                if (g[nx][ny] == 2continue;
                if (isFrie) {
                    if (fg[nx][ny] != 0continue;
                    fg[nx][ny] = fg[x][y] + offset;
                } else {
                    if (nx == n - 1 && ny == m - 1 && (fg[nx][ny] == 0 || fg[nx][ny] == pg[x][y] + offset)) ok = true;  // 火尚未到达 或 同时到达
                    if (fg[nx][ny] != 0 || pg[nx][ny] != 0continue;
                    pg[nx][ny] = pg[x][y] + offset;
                }
                deque.addLast(new int[]{nx, ny});
            }
        }
    }
}

C++ 代码:

class Solution {
public:
    vector<vector<int>> dirs = {{0,1}, {0,-1}, {1,0}, {-1,0}};
    int n, m;
    bool ok;
    vector<vector<int>> g, fg, pg;
    int maximumMinutes(vector<vector<int>>& grid) {
        g = grid;
        n = g.size(); m = g[0].size();
        fg = vector<vector<int>>(n, vector<int>(m, 0)), pg = vector<vector<int>>(n, vector<int>(m, 0));
        if (!check(0)) return -1;
        int l = 0, r = n * m;
        while (l < r) {
            int mid = l + r + 1 >> 1;
            if (check(mid)) l = mid;
            else r = mid - 1;
        }
        return r == n * m ? (int)1e9 : r;
    }
    bool check(int t) {
        ok = false;
        deque<vector<int>> frie;   
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                fg[i][j] = pg[i][j] = 0;
                if (g[i][j] == 1) {
                    fg[i][j] = 1;
                    frie.push_back({i, j});
                }
            }
        }
        while (t-- > 0) update(frie, true0);
        if (fg[0][0] != 0return false;
        deque<vector<int>> people;
        pg[0][0] = 1;
        people.push_back({00});
        while (!people.empty()) {
            update(frie, true1);
            update(people, false1);
            if (ok) return true;
        }
        return false;
    }
    void update(deque<vector<int>>& dequebool isFrie, int offset) {
        int sz = deque.size();
        while (sz-- > 0) {
            vector<int> info = deque.front();
            deque.pop_front();
            int x = info[0], y = info[1];
            for (vector<int> dir : dirs) {
                int nx = x + dir[0], ny = y + dir[1];
                if (nx < 0 || nx >= n || ny < 0 || ny >= m) continue;
                if (g[nx][ny] == 2continue;
                if (isFrie) {
                    if (fg[nx][ny] != 0continue;                    
                    fg[nx][ny] = fg[x][y] + offset;
                } else {
                    if (nx == n - 1 && ny == m - 1 && (fg[nx][ny] == 0 || fg[nx][ny] == pg[x][y] + offset)) ok = true;
                    if (fg[nx][ny] != 0 || pg[nx][ny] != 0continue;
                    pg[nx][ny] = pg[x][y] + offset;
                }
                deque.push_back({nx, ny});
            }
        }
    }
};

Python 代码:

from collections import deque

class Solution:
    def maximumMinutes(self, grid: List[List[int]]) -> int:
        dirs = [(0,1),(0,-1),(1,0),(-1,0)]
        ok = False
        g = grid
        n, m = len(g), len(g[0])
        fg, pg = [[0] * m for _ in range(n)], [[0] * m for _ in range(n)]

        def update(d, isFire, offset):
            nonlocal ok
            sz = len(d)
            for _ in range(sz):
                x, y = d.popleft()
                for di in dirs:
                    nx, ny = x + di[0], y + di[1]
                    if nx < 0 or nx >= n or ny < 0 or ny >= m:
                        continue
                    if g[nx][ny] == 2:
                        continue
                    if isFire:
                        if fg[nx][ny] != 0:
                            continue
                        fg[nx][ny] = fg[x][y] + offset
                    else:
                        if nx == n - 1 and ny == m - 1 and (fg[nx][ny] == 0 or fg[nx][ny] == pg[x][y] + offset):
                            ok = True
                        if fg[nx][ny] != 0 or pg[nx][ny] != 0:
                            continue
                        pg[nx][ny] = pg[x][y] + offset
                    d.append((nx, ny))

        def check(t):
            nonlocal ok
            ok = False
            fire = deque()
            for i in range(n):
                for j in range(m):
                    fg[i][j] = pg[i][j] = 0
                    if g[i][j] == 1:
                        fg[i][j] = 1
                        fire.append((i, j))
            for _ in range(t):
                update(fire, True0)
            if fg[0][0] != 0:
                return False
            people = deque()
            pg[0][0] = 1
            people.append((00))
            while people:
                update(fire, True1)
                update(people, False1)
                if ok:
                    return True
            return False

        if not check(0):
            return -1
        l, r = 0, n * m
        while l < r:
            mid = l + r + 1 >> 1
            if check(mid):
                l = mid
            else:
                r = mid - 1
        return int(1e9if r == n * m else r

TypeScript 代码:

function maximumMinutes(grid: number[][]): number {
    const dirs = [[0,1],[0,-1],[1,0],[-1,0]];
    const g = grid;
    const n = g.length, m = g[0].length;
    const fg = Array.from({length: n}, () => Array(m).fill(0)), pg = Array.from({length: n}, () => Array(m).fill(0));
    let ok = false;
    const update = function(d: number[][], isFire: boolean, offset: number{
        let sz = d.length;
        while (sz-- > 0) {
            const info = d.shift();
            const x = info[0], y = info[1];
            for (let di of dirs) {
                const nx = x + di[0], ny = y + di[1];
                if (nx < 0 || nx >= n || ny < 0 || ny >= m) continue;
                if (g[nx][ny] == 2continue;
                if (isFire) {
                    if (fg[nx][ny] != 0continue;
                    fg[nx][ny] = fg[x][y] + offset;
                } else {
                    if (nx == n - 1 && ny == m - 1 && (fg[nx][ny] == 0 || fg[nx][ny] == pg[x][y] + offset)) ok = true;
                    if (fg[nx][ny] != 0 || pg[nx][ny] != 0continue;
                    pg[nx][ny] = pg[x][y] + offset;
                }
                d.push([nx, ny]);
            }
        }
    }
    const check = function(t: number): boolean {
        ok = false
        const fire = new Array()
        for (let i = 0; i < n; i++) {
            for (let j = 0; j < m; j++) {
                fg[i][j] = pg[i][j] = 0;
                if (g[i][j] == 1) {
                    fg[i][j] = 1;
                    fire.push([i, j]);
                }
            }
        }
        while (t-- > 0) update(fire, true0);
        if (fg[0][0] != 0return false;
        const people = new Array();
        pg[0][0] = 1;
        people.push([00]);
        while (people.length != 0) {
            update(fire, true1);
            update(people, false1);
            if (ok) return true;
        }
        return false;
    }
    if (!check(0)) return -1;
    let l = 0, r = n * m;
    while (l < r) {
        const mid = l + r + 1 >> 1;
        if (check(mid)) l = mid;
        else r = mid - 1;
    }
    return r == n * m ? 1e9 : r;
};
  • 时间复杂度:在值域 范围内进行二分,二分 checkBFS 实现复杂度为 。整体复杂度为
  • 空间复杂度:

BFS + 分类讨论

经过上述解法,我们发现存在大量重复计算:例如每次唯一确定的“火势蔓延”过程,以及每次根据最新起始火势(由延迟出发时间 所决定)进行的“人员移动”过程,都是不必要的,可通过比较双方到达时间来求解。

具体的,还是用 fgpg,分别预处理出「火势」和「人员」到达每个网格的最早时间。其中火势蔓延唯一确定,而人员的预处理是在不考虑火势的情况下进行。

根据 进行分情况讨论:

  • :人与安全屋不连通,返回

  • :火与安全屋不连通,同时上述条件不满足( ),即人与安全屋是联通 ,返回

  • :火和人都能到达安全屋。即使不考虑人员中途被火影响(人员可能无法按照最佳路线前往安全屋)的情况下,火也比人要更早到达安全屋,返回

  • :理想情况下,人比火更早到达安全屋,但存在「人火同时到达」、「人员中途被烧」或「通路被火拦截」等问题,需要进一步分情况讨论:

    不难发现,由于安全屋的位于 ,人员只能从 两个位置之一到达安全屋(这两个属于普通位置,不允许人和火同时到达),因此可以将「对特殊位置安全屋」的讨论转为「对普通位置」的讨论:

    • ,人与该位置联通,且 ,人比火更早到达该位置,返回
    • ,人与该位置联通,且 ,人比火更早到达该位置,返回
    • 否则,说明延迟 秒出发,唯二的通路会被火提前拦截,需要早一秒出发,返回 ;

Java 代码:

class Solution {
    int[][] dirs = new int[][]{{0,1}, {0,-1}, {1,0}, {-1,0}};
    int[][] g;
    int n, m;
    public int maximumMinutes(int[][] grid) {
        g = grid;
        n = g.length; m = g[0].length;
        int[][] fg = new int[n][m], pg = new int[n][m];
        Deque<int[]> fire = new ArrayDeque<>();
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (g[i][j] == 1) {
                    fg[i][j] = 1;
                    fire.addLast(new int[]{i, j});
                }
            }
        }
        bfs(fire, fg);
        Deque<int[]> people = new ArrayDeque<>();
        people.addLast(new int[]{00});
        pg[0][0] = 1;
        bfs(people, pg);
        int p = pg[n - 1][m - 1], f = fg[n - 1][m - 1], ans = f - p;
        if (p == 0return -1;
        if (f == 0return (int)1e9;
        if (p > f) return -1;
        if (pg[n - 1][m - 2] != 0 && ans + pg[n - 1][m - 2] < fg[n - 1][m - 2]) return ans;
        if (pg[n - 2][m - 1] != 0 && ans + pg[n - 2][m - 1] < fg[n - 2][m - 1]) return ans;
        return ans - 1;
    }
    void bfs(Deque<int[]> d, int[][] time) {
        while (!d.isEmpty()) {
            int[] info = d.pollFirst();
            int x = info[0], y = info[1];
            for (int[] dir : dirs) {
                int nx = x + dir[0], ny = y + dir[1];
                if (nx < 0 || nx >= n || ny < 0 || ny >= m) continue;
                if (g[nx][ny] == 2continue;
                if (time[nx][ny] != 0continue;
                time[nx][ny] = time[x][y] + 1;
                d.addLast(new int[]{nx, ny});
            }
        }
    }
}

C++ 代码:

class Solution {
public:
    vector<vector<int>> dirs = {{0,1}, {0,-1}, {1,0}, {-1,0}};
    vector<vector<int>> g;
    int n, m;
    int maximumMinutes(vector<vector<int>>& grid) {
        g = grid;
        n = g.size(); m = g[0].size();
        vector<vector<int>> fg = vector<vector<int>>(n, vector<int>(m, 0)), pg = vector<vector<int>>(n, vector<int>(m, 0));
        deque<pair<intint>> fire;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (g[i][j] == 1) {
                    fg[i][j] = 1;
                    fire.push_back({i, j});
                }
            }
        }
        bfs(fire, fg);
        deque<pair<intint>> people;
        people.push_back({00});
        pg[0][0] = 1;
        bfs(people, pg);
        int p = pg[n - 1][m - 1], f = fg[n - 1][m - 1], ans = f - p;
        if (p == 0return -1;
        if (f == 0return (int)1e9;
        if (p > f) return -1;
        if (pg[n - 1][m - 2] != 0 && ans + pg[n - 1][m - 2] < fg[n - 1][m - 2]) return ans;
        if (pg[n - 2][m - 1] != 0 && ans + pg[n - 2][m - 1] < fg[n - 2][m - 1]) return ans;
        return ans - 1;
    }
    void bfs(deque<pair<intint>>& d, vector<vector<int>>& time) {
        while (!d.empty()) {
            pair<intint> info = d.front();
            d.pop_front();
            int x = info.first, y = info.second;
            for (vector<int> dir : dirs) {
                int nx = x + dir[0], ny = y + dir[1];
                if (nx < 0 || nx >= n || ny < 0 || ny >= m) continue;
                if (g[nx][ny] == 2continue;
                if (time[nx][ny] != 0continue;
                time[nx][ny] = time[x][y] + 1;
                d.push_back({nx, ny});
            }
        }
    }
};

Python 代码:

from collections import deque

class Solution:
    def maximumMinutes(self, grid: List[List[int]]) -> int:
        g = grid
        n, m = len(g), len(g[0])
        dirs = [(01), (0-1), (10), (-10)]

        def bfs(d, tn):
            while d:
                info = d.popleft()
                x, y = info[0], info[1]
                for dx, dy in dirs:
                    nx, ny = x + dx, y + dy
                    if nx < 0 or nx >= n or ny < 0 or ny >= m:
                        continue
                    if g[nx][ny] == 2:
                        continue
                    if tn[nx][ny]:
                        continue
                    tn[nx][ny] = tn[x][y] + 1
                    d.append((nx, ny))

        fg, pg = [[0] * m for _ in range(n)], [[0] * m for _ in range(n)]
        fire = deque()
        for i in range(n):
            for j in range(m):
                if g[i][j] == 1:
                    fg[i][j] = 1
                    fire.append((i, j))
        bfs(fire, fg)
        people = deque()
        people.append((00))
        pg[0][0] = 1
        bfs(people, pg)

        p, f = pg[-1][-1], fg[-1][-1]
        ans = f - p
        if p == 0:
            return -1
        if f == 0:
            return int(1e9)
        if p > f:
            return -1
        if pg[-1][-2] != 0 and ans + pg[-1][-2] < fg[-1][-2]:
            return ans
        if pg[-2][-1] != 0 and ans + pg[-2][-1] < fg[-2][-1]:
            return ans
        return ans - 1

TypeScript 代码:

function maximumMinutes(grid: number[][]): number {
    const g = grid;
    const n = g.length, m = g[0].length;
    const dirs = [[01], [0-1], [10], [-10]];
    const bfs = function (d: number[][], time: number[][]): void {
        while (d.length > 0) {
            const info = d.shift() as number[];
            const x = info[0], y = info[1];
            for (const dir of dirs) {
                const nx = x + dir[0], ny = y + dir[1];
                if (nx < 0 || nx >= n || ny < 0 || ny >= m) continue;
                if (g[nx][ny] == 2continue;
                if (time[nx][ny] != 0continue;
                time[nx][ny] = time[x][y] + 1;
                d.push([nx, ny]);
            }
        }
    }
    const fg = Array.from({ length: n }, () => Array(m).fill(0));
    const pg = Array.from({ length: n }, () => Array(m).fill(0));
    const fire = [];
    for (let i = 0; i < n; i++) {
        for (let j = 0; j < m; j++) {
            if (g[i][j] == 1) {
                fg[i][j] = 1;
                fire.push([i, j]);
            }
        }
    }
    bfs(fire, fg);
    const people = [];
    people.push([00]);
    pg[0][0] = 1;
    bfs(people, pg);
    const p = pg[n - 1][m - 1], f = fg[n - 1][m - 1], ans = f - p;
    if (p == 0return -1;
    if (f == 0return 1e9;
    if (p > f) return -1;
    if (pg[n - 1][m - 2] != 0 && ans + pg[n - 1][m - 2] < fg[n - 1][m - 2]) return ans;
    if (pg[n - 2][m - 1] != 0 && ans + pg[n - 2][m - 1] < fg[n - 2][m - 1]) return ans;
    return ans - 1;
};
  • 时间复杂度:
  • 空间复杂度:

最后

这是我们「刷穿 LeetCode」系列文章的第 No.2258 篇,系列开始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完。

在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。

为了方便各位同学能够电脑上进行调试和提交代码,我建立了相关的仓库:https://github.com/SharingSource/LogicStack-LeetCode 。

在仓库地址里,你可以看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其他优选题解。

更多更全更热门的「笔试/面试」相关资料可访问排版精美的 合集新基地 🎉🎉

本文由 mdnice 多平台发布

相关文章:

2258. 逃离火灾 : 详解如何从「二分」到「分类讨论」(图解过程)

题目描述 这是 LeetCode 上的 「2258. 逃离火灾」 &#xff0c;难度为 「困难」。 Tag : 「多源 BFS」、「二分」、「预处理」 给你一个下标从 0 开始大小为 m x n 的二维整数数组 grid&#xff0c;它表示一个网格图。 每个格子为下面 个值之一&#xff1a; 0 表示草地。 1 表…...

基于SSM框架的共享单车管理系统小程序系统的设计和实现

基于SSM框架的共享单车管理系统小程序系统的设计和实现 源码传送入口前言主要技术系统设计功能截图Lun文目录订阅经典源码专栏Java项目精品实战案例《500套》 源码获取 源码传送入口 前言 随着科学技术的飞速发展&#xff0c;各行各业都在努力与现代先进技术接轨&#xff0c;…...

COOHOM通过采用亚马逊云科“专库专用”的方式,为云原生的构建提供稳定的数据支撑

全球化浪潮下&#xff0c;面对全球化业务发展带来的新需求与新挑战&#xff0c;越来越多的企业开启了云原生构建旅程&#xff0c;以推动业务系统快速迭代&#xff0c;为国际业务的拓展打下坚实的基础。COOHOM是杭州群核信息技术有限公司旗下的国际化品牌。为全球企业和个人提供…...

Java根据一个List内Object的两个字段去重

背景 在Java开发过程中&#xff0c;我们经常会遇到需要对List进行去重的需求。 其中常见的情况是&#xff0c;将数组去重&#xff0c;或者将对象依据某个字段去重。这两种方式均可用set属性进行处理。 今天讨论&#xff0c;有一个List&#xff0c;且其中的元素是自定义的对象&…...

运维那些事儿|2023年,运维还有出路吗?

作为一名运维&#xff0c;不知道你有没有这样的感受。 觉得自己的工作没什么成长空间。每天装个系统、跑个机房、跑个脚本&#xff0c;忙来忙去也没忙出来什么名堂&#xff0c;含金量低不说&#xff0c;薪资也一直没见涨&#xff0c;所以你开始陷入迷茫&#xff0c;会疑惑&…...

数据结构——二叉树(2)

接上一篇文章http://t.csdnimg.cn/nsKsW&#xff0c;本次我们接着讲解关于二叉树的相关知识。 一、二叉树的相关性质&#xff1a; 1. 若规定根节点的层数为 1 &#xff0c;则一棵非空二叉树的 第 i 层上最多有 2^(i-1) 个结点. 2. 若规定根节点的层数为 1 &#xff0c;则 深度…...

aosp定制android系统

目录 AOSP 准备工作(配置) 确定机型和版本 初始化 git安装 curl安装 同步源码 环境变量 创建aosp目录 指定同步版本 解下来安装编译需要的依赖 编译aosp源码 刷入系统 AOSP 全称 Android Open Source Project 是指Android开源项目&#xff0c;它是由Google主导的…...

程序员的护城河:构建数字世界的守护者

目录 前言1 持续学习的愿望和能力2 与他人沟通和合作的能力3 追求技术的深度和广度4 具备分享的精神结语 前言 在数字化时代&#xff0c;程序员是现代社会的护城河。他们的工作不仅是构建应用程序和系统&#xff0c;更是为保障系统安全、数据防护以及网络稳定发挥着至关重要的…...

Sample Average Approximation,SAA

1. sample average approximation,SAA “样本平均近似”&#xff08;Sample Average Approximation&#xff0c;SAA&#xff09;方法是数学优化和运筹学领域广泛使用的优化技术。它主要用于处理优化问题的目标函数或约束涉及随机或不确定参数的情况。SAA尤其适用于具有随机或概…...

springbootMysql文华学院青年志愿者服务预约系统97973-计算机毕业设计项目选题推荐(附源码)

摘 要 随着社会的发展&#xff0c;社会的各行各业都在利用信息化时代的优势。计算机的优势和普及使得各种信息系统的开发成为必需。 文华学院青年志愿者服务预约系统&#xff0c;主要的模块包括管理员&#xff1a;后台首页、轮播图、通知公告管理、资源管理&#xff08;新闻资…...

Go 语言向函数传递数组

Go 语言向函数传递数组 在 Go 语言中&#xff0c;数组是值类型&#xff0c;因此将数组传递给函数时&#xff0c;将复制整个数组。如果数组非常大&#xff0c;这可能会导致性能问题。为了避免复制整个数组&#xff0c;可以通过传递切片&#xff08;Slice&#xff09;来传递数组…...

高压放大器在铁电测试中的用途有哪些

高压放大器在铁电测试中有多种重要用途。铁电材料是指具有自发极化的晶体材料&#xff0c;具有一系列特殊的电学和物理性质。铁电测试是研究铁电材料性质的关键实验手段之一。下面安泰电子将介绍高压放大器在铁电测试中的几个主要用途。 极化场施加&#xff1a;铁电材料的最显著…...

一款高效、简洁的数据处理和清洗加工工具,值得收藏!

随着数字化时代的快速发展&#xff0c;数据已经成为企业运营和决策的重要依据。然而&#xff0c;处理和分析大量复杂数据是一个具有挑战性的任务&#xff0c;特别是在数据清洗和加工环节。为了满足这一需求&#xff0c;JVS-BI提供了一套高效、简洁的数据处理和分析解决方案。 …...

很多个pdf怎么合并在一起?

很多个pdf怎么合并在一起&#xff1f;作为一个办公室的伙伴&#xff0c;对于PDF格式肯定不会陌生。它强大的功能为我们的工作提供了许多便利。由于PDF文件格式的稳定性和安全性较高&#xff0c;我们通常在工作或学习中使用它来传输文件&#xff0c;很多人都喜欢将办公文件都做成…...

Ubuntu apt更换国内镜像源,apt 更新源,apt 国内镜像

详细一篇&#xff1a; https://midoq.github.io/2022/05/30/Ubuntu20-04%E6%9B%B4%E6%8D%A2%E5%9B%BD%E5%86%85%E9%95%9C%E5%83%8F%E6%BA%90/ 更换方法 Ubuntu采用apt作为软件安装工具&#xff0c;其镜像源列表记录在/etc/apt/source.list文件中。 首先将source.list复制为s…...

时序预测 | MATLAB实现WOA-CNN-BiLSTM-Attention时间序列预测(SE注意力机制)

时序预测 | MATLAB实现WOA-CNN-BiLSTM-Attention时间序列预测&#xff08;SE注意力机制&#xff09; 目录 时序预测 | MATLAB实现WOA-CNN-BiLSTM-Attention时间序列预测&#xff08;SE注意力机制&#xff09;预测效果基本描述模型描述程序设计参考资料 预测效果 基本描述 1.MAT…...

VINS-Mono-后端优化 (一:预积分残差计算-IMU预积分约束)

这里先回顾一下预积分是怎么来的 VINS-Mono-IMU预积分 &#xff08;三&#xff1a;为什么要预积分预积分推导&#xff09; 这里贴出预积分的公式 具体含义解释看对对应的文章 整个误差函数如下 预积分 α \alpha α β \beta β γ \gamma γ 是用 IMU 预积分获得的增量&a…...

怎么调整excel表里面所有单元格中,某个相同字体大小,单元格中其他文字大小不变?

环境: excel 2021 python3.8 问题描述: 怎么调整excel表里面所有单元格里面1这个字体大小,单元格里面其他文字不变? excel表里面。很多单元格都有1,1和文字都是10号字体,现在想把全部1字字体调整为16号其他字大小都不变 解决方案: 一、使用python来实现,经过测…...

流式数据库引擎备受关注,亚信安慧AntDB数据库受邀参加“2023中国PostgreSQL数据库生态大会”

11月3日至5日&#xff0c;2023中国PostgreSQL数据库生态大会在北京中科院软件所大报告厅盛大召开&#xff0c;大会现场百余位专家学者、企业、用户代表及线上数千位观众&#xff0c;就近年来国产数据库技术与市场变革进行深入探讨。湖南亚信安慧科技有限公司&#xff08;简称&a…...

kafka开启SSL认证(包括内置zookeeper开启SSL)

zookeeper和kafka的SSL开启都可单独进行 生成SSL证书 使用jre自带的keytool工具生成&#xff0c;linux和windows下生成的证书可以通用 生成含有一个私钥的keystore文件&#xff0c;有效期10年&#xff08;本文证书密码统一使用test123&#xff09; keytool -genkeypair -ali…...

第19节 Node.js Express 框架

Express 是一个为Node.js设计的web开发框架&#xff0c;它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用&#xff0c;和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...

装饰模式(Decorator Pattern)重构java邮件发奖系统实战

前言 现在我们有个如下的需求&#xff0c;设计一个邮件发奖的小系统&#xff0c; 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式&#xff08;Decorator Pattern&#xff09;允许向一个现有的对象添加新的功能&#xff0c;同时又不改变其…...

React19源码系列之 事件插件系统

事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…...

Nginx server_name 配置说明

Nginx 是一个高性能的反向代理和负载均衡服务器&#xff0c;其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机&#xff08;Virtual Host&#xff09;。 1. 简介 Nginx 使用 server_name 指令来确定…...

ServerTrust 并非唯一

NSURLAuthenticationMethodServerTrust 只是 authenticationMethod 的冰山一角 要理解 NSURLAuthenticationMethodServerTrust, 首先要明白它只是 authenticationMethod 的选项之一, 并非唯一 1 先厘清概念 点说明authenticationMethodURLAuthenticationChallenge.protectionS…...

SpringCloudGateway 自定义局部过滤器

场景&#xff1a; 将所有请求转化为同一路径请求&#xff08;方便穿网配置&#xff09;在请求头内标识原来路径&#xff0c;然后在将请求分发给不同服务 AllToOneGatewayFilterFactory import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; impor…...

中医有效性探讨

文章目录 西医是如何发展到以生物化学为药理基础的现代医学&#xff1f;传统医学奠基期&#xff08;远古 - 17 世纪&#xff09;近代医学转型期&#xff08;17 世纪 - 19 世纪末&#xff09;​现代医学成熟期&#xff08;20世纪至今&#xff09; 中医的源远流长和一脉相承远古至…...

PAN/FPN

import torch import torch.nn as nn import torch.nn.functional as F import mathclass LowResQueryHighResKVAttention(nn.Module):"""方案 1: 低分辨率特征 (Query) 查询高分辨率特征 (Key, Value).输出分辨率与低分辨率输入相同。"""def __…...

C++课设:简易日历程序(支持传统节假日 + 二十四节气 + 个人纪念日管理)

名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 专栏介绍:《编程项目实战》 目录 一、为什么要开发一个日历程序?1. 深入理解时间算法2. 练习面向对象设计3. 学习数据结构应用二、核心算法深度解析…...

NPOI操作EXCEL文件 ——CAD C# 二次开发

缺点:dll.版本容易加载错误。CAD加载插件时&#xff0c;没有加载所有类库。插件运行过程中用到某个类库&#xff0c;会从CAD的安装目录找&#xff0c;找不到就报错了。 【方案2】让CAD在加载过程中把类库加载到内存 【方案3】是发现缺少了哪个库&#xff0c;就用插件程序加载进…...