【题解】—— LeetCode一周小结47

简介: LeetCode每日一道一周小结47

🌟欢迎来到 我的博客 —— 探索技术的无限可能!

🌟博客的简介(文章目录)


【题解】—— 每日一道题目栏


上接:【题解】—— LeetCode一周小结46

18.图片平滑器

题目链接:661. 图片平滑器

图像平滑器 是大小为 3 x 3 的过滤器,用于对图像的每个单元格平滑处理,平滑处理后单元格的值为该单元格的平均灰度。

每个单元格的 平均灰度 定义为:该单元格自身及其周围的 8 个单元格的平均值,结果需向下取整。(即,需要计算蓝色平滑器中 9 个单元格的平均值)。

如果一个单元格周围存在单元格缺失的情况,则计算平均灰度时不考虑缺失的单元格(即,需要计算红色平滑器中 4 个单元格的平均值)。

给你一个表示图像灰度的 m x n 整数矩阵 img ,返回对图像的每个单元格平滑处理后的图像 。

示例 1:

输入:img = [[1,1,1],[1,0,1],[1,1,1]]

输出:[[0, 0, 0],[0, 0, 0], [0, 0, 0]]

解释:

对于点 (0,0), (0,2), (2,0), (2,2): 平均(3/4) = 平均(0.75) = 0

对于点 (0,1), (1,0), (1,2), (2,1): 平均(5/6) = 平均(0.83333333) = 0

对于点 (1,1): 平均(8/9) = 平均(0.88888889) = 0

示例 2:

输入: img = [[100,200,100],[200,50,200],[100,200,100]]

输出: [[137,141,137],[141,138,141],[137,141,137]]

解释:

对于点 (0,0), (0,2), (2,0), (2,2): floor((100+200+200+50)/4) =

floor(137.5) = 137

对于点 (0,1), (1,0), (1,2), (2,1): floor((200+200+50+200+100+100)/6) =

floor(141.666667) = 141

对于点 (1,1): floor((50+200+200+200+200+100+100+100+100)/9) =

floor(138.888889) = 138

提示:

m == img.length

n == img[i].length

1 <= m, n <= 200

0 <= img[i][j] <= 255

题解:

方法:前缀和

       

class Solution {
    public int[][] imageSmoother(int[][] img) {
        int m = img.length, n = img[0].length;
        int[][] ans = new int[m][n];
        int[][] dirs = new int[][]{{0,0},{1,0},{-1,0},{0,1},{0,-1},{-1,-1},{-1,1},{1,-1},{1,1}};
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                int tot = 0, cnt = 0;
                for (int[] di : dirs) {
                    int nx = i + di[0], ny = j + di[1];
                    if (nx < 0 || nx >= m || ny < 0 || ny >= n) continue;
                    tot += img[nx][ny]; cnt++;
                }
                ans[i][j] = tot / cnt;
            }
        }
        return ans;
    }
}

19.新增道路查询后的最短距离 I

题目链接:3243. 新增道路查询后的最短距离 I

给你一个整数 n 和一个二维整数数组 queries。

有 n 个城市,编号从 0 到 n - 1。初始时,每个城市 i 都有一条单向道路通往城市 i + 1( 0 <= i < n - 1)。

queries[i] = [ui, vi] 表示新建一条从城市 ui 到城市 vi 的单向道路。每次查询后,你需要找到从城市 0 到城市 n - 1 的最短路径的长度。

返回一个数组 answer,对于范围 [0, queries.length - 1] 中的每个 i,answer[i] 是处理完前 i + 1 个查询后,从城市 0 到城市 n - 1 的最短路径的长度。

示例 1:

输入: n = 5, queries = [[2, 4], [0, 2], [0, 4]]

输出: [3, 2, 1]

解释:

新增一条从 2 到 4 的道路后,从 0 到 4 的最短路径长度为 3。

新增一条从 0 到 2 的道路后,从 0 到 4 的最短路径长度为 2。

新增一条从 0 到 4 的道路后,从 0 到 4 的最短路径长度为 1。

示例 2:

输入: n = 4, queries = [[0, 3], [0, 2]]

输出: [1, 1]

解释:

新增一条从 0 到 3 的道路后,从 0 到 3 的最短路径长度为 1。

新增一条从 0 到 2 的道路后,从 0 到 3 的最短路径长度仍为 1。

提示:

3 <= n <= 500

1 <= queries.length <= 500

queries[i].length == 2

0 <= queries[i][0] < queries[i][1] < n

1 < queries[i][1] - queries[i][0]

查询中没有重复的道路。

题解:

方法:DP

       

class Solution {
    public int[] shortestDistanceAfterQueries(int n, int[][] queries) {
        List<Integer>[] from = new ArrayList[n];
        Arrays.setAll(from, i -> new ArrayList<>());
        int[] f = new int[n];
        for (int i = 1; i < n; i++) {
            f[i] = i;
        }
        int[] ans = new int[queries.length];
        for (int qi = 0; qi < queries.length; qi++) {
            int l = queries[qi][0];
            int r = queries[qi][1];
            from[r].add(l);
            if (f[l] + 1 < f[r]) {
                f[r] = f[l] + 1;
                for (int i = r + 1; i < n; i++) {
                    f[i] = Math.min(f[i], f[i - 1] + 1);
                    for (int j : from[i]) {
                        f[i] = Math.min(f[i], f[j] + 1);
                    }
                }
            }
            ans[qi] = f[n - 1];
        }
        return ans;
    }
}

20.新增道路查询后的最短距离 II

题目链接:3244. 新增道路查询后的最短距离 II

class UnionFind {

public final int[] fa;

public UnionFind(int size) {
    fa = new int[size];
    for (int i = 1; i < size; i++) {
        fa[i] = i;
    }
}
public int find(int x) {
    if (fa[x] != x) {
        fa[x] = find(fa[x]);
    }
    return fa[x];
}

}

class Solution {

public int[] shortestDistanceAfterQueries(int n, int[][] queries) {

UnionFind uf = new UnionFind(n - 1);

int[] ans = new int[queries.length];

int cnt = n - 1; // 并查集连通块个数

for (int qi = 0; qi < queries.length; qi++) {

int l = queries[qi][0];

int r = queries[qi][1] - 1;

int fr = uf.find®;

for (int i = uf.find(l); i < r; i = uf.find(i + 1)) {

uf.fa[i] = fr;

cnt–;

}

ans[qi] = cnt;

}

return ans;

}

}

作者:灵茶山艾府

链接:https://leetcode.cn/problems/shortest-distance-after-road-addition-queries-ii/solutions/2868558/qu-jian-bing-cha-ji-pythonjavacgo-by-end-a9k7/

来源:力扣(LeetCode)

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

题解:

方法:区间并查集

       

class UnionFind {
    public final int[] fa;
    public UnionFind(int size) {
        fa = new int[size];
        for (int i = 1; i < size; i++) {
            fa[i] = i;
        }
    }
    public int find(int x) {
        if (fa[x] != x) {
            fa[x] = find(fa[x]);
        }
        return fa[x];
    }
}
class Solution {
    public int[] shortestDistanceAfterQueries(int n, int[][] queries) {
        UnionFind uf = new UnionFind(n - 1);
        int[] ans = new int[queries.length];
        int cnt = n - 1; // 并查集连通块个数
        for (int qi = 0; qi < queries.length; qi++) {
            int l = queries[qi][0];
            int r = queries[qi][1] - 1;
            int fr = uf.find(r);
            for (int i = uf.find(l); i < r; i = uf.find(i + 1)) {
                uf.fa[i] = fr;
                cnt--;
            }
            ans[qi] = cnt;
        }
        return ans;
    }
}

21.矩阵中的蛇

题目链接:3248. 矩阵中的蛇

大小为 n x n 的矩阵 grid 中有一条蛇。蛇可以朝 四个可能的方向 移动。矩阵中的每个单元格都使用位置进行标识: grid[i][j] = (i * n) + j。

蛇从单元格 0 开始,并遵循一系列命令移动。

给你一个整数 n 表示 grid 的大小,另给你一个字符串数组 commands,其中包括 “UP”、“RIGHT”、“DOWN” 和 “LEFT”。题目测评数据保证蛇在整个移动过程中将始终位于 grid 边界内。

返回执行 commands 后蛇所停留的最终单元格的位置。

示例 1:

输入:n = 2, commands = [“RIGHT”,“DOWN”]

输出:3

解释:

0 1

2 3

0 1

2 3

0 1

2 3

示例 2:

输入:n = 3, commands = [“DOWN”,“RIGHT”,“UP”]

输出:1

解释:

0 1 2

3 4 5

6 7 8

0 1 2

3 4 5

6 7 8

0 1 2

3 4 5

6 7 8

0 1 2

3 4 5

6 7 8

提示:

2 <= n <= 10

1 <= commands.length <= 100

commands 仅由 “UP”、“RIGHT”、“DOWN” 和 “LEFT” 组成。

生成的测评数据确保蛇不会移动到矩阵的边界外。

题解:

方法:****

       

class Solution {
    public int finalPositionOfSnake(int n, List<String> commands) {
        int i = 0;
        int j = 0;
        for (String s : commands) {
            switch (s.charAt(0)) {
                case 'U' -> i--;
                case 'D' -> i++;
                case 'L' -> j--;
                default  -> j++;
            }
        }
        return i * n + j;
    }
}

22.统计不是特殊数字的数字数量

题目链接:3233. 统计不是特殊数字的数字数量

给你两个 正整数 l 和 r。对于任何数字 x,x 的所有正因数(除了 x 本身)被称为 x 的 真因数。

如果一个数字恰好仅有两个 真因数,则称该数字为 特殊数字。例如:

数字 4 是 特殊数字,因为它的真因数为 1 和 2。

数字 6 不是 特殊数字,因为它的真因数为 1、2 和 3。

返回区间 [l, r] 内 不是 特殊数字 的数字数量。

示例 1:

输入: l = 5, r = 7

输出: 3

解释:

区间 [5, 7] 内不存在特殊数字。

示例 2:

输入: l = 4, r = 16

输出: 11

解释:

区间 [4, 16] 内的特殊数字为 4 和 9。

提示:

1 <= l <= r <= 109

题解:

方法:数学

       

class Solution {
    private static final int MX = 31622;
    private static final int[] PI = new int[MX + 1];
    static {
        for (int i = 2; i <= MX; i++) {
            if (PI[i] == 0) { // i 是质数
                PI[i] = PI[i - 1] + 1;
                for (int j = i * i; j <= MX; j += i) { // 注:如果 MX 比较大,小心 i*i 溢出
                    PI[j] = -1; // 标记 i 的倍数为合数
                }
            } else {
                PI[i] = PI[i - 1];
            }
        }
    }
    public int nonSpecialCount(int l, int r) {
        return r - l + 1 - (PI[(int) Math.sqrt(r)] - PI[(int) Math.sqrt(l - 1)]);
    }
}

23.求出胜利玩家的数目

题目链接:3238. 求出胜利玩家的数目

给你一个整数 n ,表示在一个游戏中的玩家数目。同时给你一个二维整数数组 pick ,其中 pick[i] = [xi, yi] 表示玩家 xi 获得了一个颜色为 yi 的球。

如果玩家 i 获得的球中任何一种颜色球的数目 严格大于 i 个,那么我们说玩家 i 是胜利玩家。换句话说:

如果玩家 0 获得了任何的球,那么玩家 0 是胜利玩家。

如果玩家 1 获得了至少 2 个相同颜色的球,那么玩家 1 是胜利玩家。

如果玩家 i 获得了至少 i + 1 个相同颜色的球,那么玩家 i 是胜利玩家。

请你返回游戏中 胜利玩家 的数目。

注意,可能有多个玩家是胜利玩家。

示例 1:

输入:n = 4, pick = [[0,0],[1,0],[1,0],[2,1],[2,1],[2,0]]

输出:2

解释:

玩家 0 和玩家 1 是胜利玩家,玩家 2 和玩家 3 不是胜利玩家。

示例 2:

输入:n = 5, pick = [[1,1],[1,2],[1,3],[1,4]]

输出:0

解释:

没有胜利玩家。

示例 3:

输入:n = 5, pick = [[1,1],[2,4],[2,4],[2,4]]

输出:1

解释:

玩家 2 是胜利玩家,因为玩家 2 获得了 3 个颜色为 4 的球。

提示:

2 <= n <= 10

1 <= pick.length <= 100

pick[i].length == 2

0 <= xi <= n - 1

0 <= yi <= 10

题解:

方法:两次遍历

       

class Solution {
    public int winningPlayerCount(int n, int[][] pick) {
        int[][] cnts = new int[n][11];
        for (int[] p : pick) {
            cnts[p[0]][p[1]]++;
        }
        int ans = 0;
        for (int i = 0; i < n; i++) {
            for (int c : cnts[i]) {
                if (c > i) {
                    ans++;
                    break;
                }
            }
        }
        return ans;
    }
}

24.最小区间

题目链接:632. 最小区间

你有 k 个 非递减排列 的整数列表。找到一个 最小 区间,使得 k 个列表中的每个列表至少有一个数包含在其中。

我们定义如果 b-a < d-c 或者在 b-a == d-c 时 a < c,则区间 [a,b] 比 [c,d] 小。

示例 1:

输入:nums = [[4,10,15,24,26], [0,9,12,20], [5,18,22,30]]

输出:[20,24]

解释:

列表 1:[4, 10, 15, 24, 26],24 在区间 [20,24] 中。

列表 2:[0, 9, 12, 20],20 在区间 [20,24] 中。

列表 3:[5, 18, 22, 30],22 在区间 [20,24] 中。

示例 2:

输入:nums = [[1,2,3],[1,2,3],[1,2,3]]

输出:[1,1]

提示:

nums.length == k

1 <= k <= 3500

1 <= nums[i].length <= 50

-105 <= nums[i][j] <= 105

nums[i] 按非递减顺序排列

题解:

方法:滑动窗口

       

class Solution {
    public int[] smallestRange(List<List<Integer>> nums) {
        int sumLen = 0;
        for (List<Integer> list : nums) {
            sumLen += list.size();
        }
        int[][] pairs = new int[sumLen][2];
        int pi = 0;
        for (int i = 0; i < nums.size(); i++) {
            for (int x : nums.get(i)) {
                pairs[pi][0] = x;
                pairs[pi++][1] = i;
            }
        }
        Arrays.sort(pairs, (a, b) -> a[0] - b[0]);
        int ansL = pairs[0][0];
        int ansR = pairs[sumLen - 1][0];
        int empty = nums.size();
        int[] cnt = new int[empty];
        int left = 0;
        for (int[] p : pairs) {
            int r = p[0];
            int i = p[1];
            if (cnt[i] == 0) { // 包含 nums[i] 的数字
                empty--;
            }
            cnt[i]++;
            while (empty == 0) { // 每个列表都至少包含一个数
                int l = pairs[left][0];
                if (r - l < ansR - ansL) {
                    ansL = l;
                    ansR = r;
                }
                i = pairs[left][1];
                cnt[i]--;
                if (cnt[i] == 0) { // 不包含 nums[i] 的数字
                    empty++;
                }
                left++;
            }
        }
        return new int[]{ansL, ansR};
    }
}

下接:【题解】—— LeetCode一周小结48


相关文章
|
18天前
|
机器学习/深度学习
|
18天前
|
人工智能 BI
|
3月前
|
机器人
|
6月前
|
算法

热门文章

最新文章