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

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

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


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


上接:【题解】------ LeetCode一周小结26

2024.7

1.最大化一张图中的路径价值

题目链接:2065. 最大化一张图中的路径价值

给你一张 无向 图,图中有 n 个节点,节点编号从 0 到 n - 1 (都包括)。同时给你一个下标从 0 开始的整数数组 values ,其中 valuesi 是第 i 个节点的 价值 。同时给你一个下标从 0 开始的二维整数数组 edges ,其中 edgesj = uj, vj, timej 表示节点 uj 和 vj 之间有一条需要 timej 秒才能通过的无向边。最后,给你一个整数 maxTime 。

合法路径 指的是图中任意一条从节点 0 开始,最终回到节点 0 ,且花费的总时间 不超过 maxTime 秒的一条路径。你可以访问一个节点任意次。一条合法路径的 价值 定义为路径中 不同节点 的价值 之和 (每个节点的价值 至多 算入价值总和中一次)。

请你返回一条合法路径的 最大 价值。

注意:每个节点 至多 有 四条 边与之相连。

示例 1:

输入:values = 0,32,10,43, edges = \[0,1,10,1,2,15,0,3,10],

maxTime = 49

输出:75

解释:

一条可能的路径为:0 -> 1 -> 0 -> 3 -> 0 。总花费时间为 10 + 10 + 10 + 10 = 40 <= 49 。

访问过的节点为 0 ,1 和 3 ,最大路径价值为 0 + 32 + 43 = 75 。

示例 2:

输入:values = 5,10,15,20, edges = \[0,1,10,1,2,10,0,3,10],

maxTime = 30

输出:25

解释:

一条可能的路径为:0 -> 3 -> 0 。总花费时间为 10 + 10 = 20 <= 30 。

访问过的节点为 0 和 3 ,最大路径价值为 5 + 20 = 25 。

示例 3:

输入:values = 1,2,3,4, edges = \[0,1,10,1,2,11,2,3,12,1,3,13],

maxTime = 50

输出:7

解释:

一条可能的路径为:0 -> 1 -> 3 -> 1 -> 0 。总花费时间为 10 + 13 + 13 + 10 = 46 <= 50 。

访问过的节点为 0 ,1 和 3 ,最大路径价值为 1 + 2 + 4 = 7 。

示例 4:

输入:values = 0,1,2, edges = \[1,2,10], maxTime = 10

输出:0

解释:

唯一一条路径为 0 。总花费时间为 0 。

唯一访问过的节点为 0 ,最大路径价值为 0 。

提示:

n == values.length

1 <= n <= 1000

0 <= valuesi <= 108

0 <= edges.length <= 2000

edgesj.length == 3

0 <= uj < vj <= n - 1

10 <= timej, maxTime <= 100

uj, vj 所有节点对 互不相同 。

每个节点 至多有四条 边。

图可能不连通。

题解:

方法:最短路剪枝

java 复制代码
public class Solution {
    public int maximalPathQuality(int[] values, int[][] edges, int maxTime) {
        int n = values.length;
        List<int[]>[] g = new ArrayList[n];
        Arrays.setAll(g, i -> new ArrayList<>());
        for (int[] e : edges) {
            int x = e[0];
            int y = e[1];
            int t = e[2];
            g[x].add(new int[]{y, t});
            g[y].add(new int[]{x, t});
        }

        // Dijkstra 算法
        int[] dis = new int[n];
        Arrays.fill(dis, Integer.MAX_VALUE);
        dis[0] = 0;
        PriorityQueue<int[]> pq = new PriorityQueue<>((a, b) -> a[0] - b[0]);
        pq.add(new int[]{0, 0});
        while (!pq.isEmpty()) {
            int[] p = pq.poll();
            int dx = p[0];
            int x = p[1];
            if (dx > dis[x]) { // x 之前出堆过
                continue;
            }
            for (int[] e : g[x]) {
                int y = e[0];
                int newDis = dx + e[1];
                if (newDis < dis[y]) {
                    dis[y] = newDis; // 更新 x 的邻居的最短路
                    pq.offer(new int[]{newDis, y});
                }
            }
        }

        boolean[] vis = new boolean[n];
        vis[0] = true;
        return dfs(0, 0, values[0], vis, g, values, maxTime, dis);
    }

    private int dfs(int x, int sumTime, int sumValue, boolean[] vis, List<int[]>[] g, int[] values, int maxTime, int[] dis) {
        int res = x == 0 ? sumValue : 0;
        for (int[] e : g[x]) {
            int y = e[0];
            int t = e[1];
            // 相比方法一,这里多了 dis[y]
            if (sumTime + t + dis[y] > maxTime) {
                continue;
            }
            if (vis[y]) {
                res = Math.max(res, dfs(y, sumTime + t, sumValue, vis, g, values, maxTime, dis));
            } else {
                vis[y] = true;
                // 每个节点的价值至多算入价值总和中一次
                res = Math.max(res, dfs(y, sumTime + t, sumValue + values[y], vis, g, values, maxTime, dis));
                vis[y] = false; // 恢复现场
            }
        }
        return res;
    }
}

2.质数的最大距离

题目链接:3115. 质数的最大距离

给你一个整数数组 nums。

返回两个(不一定不同的)质数在 nums 中 下标 的 最大距离。

示例 1:

输入: nums = 4,2,9,5,3

输出: 3

解释: nums1、nums3 和 nums4 是质数。因此答案是 |4 - 1| = 3。

示例 2:

输入: nums = 4,8,2,8

输出: 0

解释: nums2 是质数。因为只有一个质数,所以答案是 |2 - 2| = 0。

提示:

1 <= nums.length <= 3 * 105

1 <= numsi <= 100

输入保证 nums 中至少有一个质数。

题解:

方法:判断质数

java 复制代码
class Solution {
    public int maximumPrimeDifference(int[] nums) {
        int i = 0;
        while (!isPrime(nums[i])) {
            i++;
        }
        int j = nums.length - 1;
        while (!isPrime(nums[j])) {
            j--;
        }
        return j - i;
    }

    private boolean isPrime(int n) {
        for (int i = 2; i * i <= n; i++) {
            if (n % i == 0) {
                return false;
            }
        }
        return n >= 2;
    }
}

3.哈沙德数

题目链接:3099. 哈沙德数

如果一个整数能够被其各个数位上的数字之和整除,则称之为 哈沙德数(Harshad number)。给你一个整数 x 。如果 x 是 哈沙德数 ,则返回 x 各个数位上的数字之和,否则,返回 -1 。

示例 1:

输入: x = 18

输出: 9

解释:

x 各个数位上的数字之和为 9 。18 能被 9 整除。因此 18 是哈沙德数,答案是 9 。

示例 2:

输入: x = 23

输出: -1

解释:

x 各个数位上的数字之和为 5 。23 不能被 5 整除。因此 23 不是哈沙德数,答案是 -1 。

提示:

1 <= x <= 100

题解:

方法:模拟

java 复制代码
class Solution {
    public int sumOfTheDigitsOfHarshadNumber(int x) {
        int s = 0;
        for (int y = x; y > 0; y /= 10) {
            s += y % 10;
        }
        return x % s == 0 ? s : -1;
    }
}

4.拾起 K 个 1 需要的最少行动次数

题目链接:3086. 拾起 K 个 1 需要的最少行动次数

给你一个下标从 0 开始的二进制数组 nums,其长度为 n ;另给你一个 正整数 k 以及一个 非负整数 maxChanges 。

Alice 在玩一个游戏,游戏的目标是让 Alice 使用 最少 数量的 行动 次数从 nums 中拾起 k 个 1 。游戏开始时,Alice 可以选择数组 0, n - 1 范围内的任何索引 aliceIndex 站立。如果 numsaliceIndex == 1 ,Alice 会拾起一个 1 ,并且 numsaliceIndex 变成0(这 不算 作一次行动)。之后,Alice 可以执行 任意数量 的 行动(包括零次),在每次行动中 Alice 必须 恰好 执行以下动作之一:

选择任意一个下标 j != aliceIndex 且满足 numsj == 0 ,然后将 numsj 设置为 1 。这个动作最多可以执行 maxChanges 次。

选择任意两个相邻的下标 x 和 y(|x - y| == 1)且满足 numsx == 1, numsy == 0 ,然后交换它们的值(将 numsy = 1 和 numsx = 0)。如果 y == aliceIndex,在这次行动后 Alice 拾起一个 1 ,并且 numsy 变成 0 。

返回 Alice 拾起 恰好 k 个 1 所需的 最少 行动次数。

示例 1:

输入:nums = 1,1,0,0,0,1,1,0,0,1, k = 3, maxChanges = 1

输出:3

解释:如果游戏开始时 Alice 在 aliceIndex == 1 的位置上,按照以下步骤执行每个动作,他可以利用 3 次行动拾取 3 个

1 :

游戏开始时 Alice 拾取了一个 1 ,nums1 变成了 0。此时 nums 变为 1,0,1,0,0,1,1,0,0,1

选择 j == 2 并执行第一种类型的动作。nums 变为 1,0,1,0,0,1,1,0,0,1

选择 x == 2 和 y == 1 ,并执行第二种类型的动作。nums 变为 1,1,0,0,0,1,1,0,0,1 。由于 y ==

aliceIndex,Alice 拾取了一个 1 ,nums 变为 1,0,0,0,0,1,1,0,0,1

选择 x == 0 和 y == 1 ,并执行第二种类型的动作。nums 变为 0,1,0,0,0,1,1,0,0,1 。由于 y ==

aliceIndex,Alice 拾取了一个 1 ,nums 变为 0,0,0,0,0,1,1,0,0,1

请注意,Alice 也可能执行其他的 3 次行动序列达成拾取 3 个 1 。

示例 2:

输入:nums = 0,0,0,0, k = 2, maxChanges = 3

输出:4

解释:如果游戏开始时 Alice 在 aliceIndex == 0 的位置上,按照以下步骤执行每个动作,他可以利用 4 次行动拾取 2 个

1 :

选择 j == 1 并执行第一种类型的动作。nums 变为 0,1,0,0

选择 x == 1 和 y == 0 ,并执行第二种类型的动作。nums 变为 1,0,0,0 。由于 y ==

aliceIndex,Alice 拾起了一个 1 ,nums 变为 0,0,0,0

再次选择 j == 1 并执行第一种类型的动作。nums 变为 0,1,0,0

再次选择 x == 1 和 y == 0 ,并执行第二种类型的动作。nums 变为 1,0,0,0 。由于y ==

aliceIndex,Alice 拾起了一个 1 ,nums 变为 0,0,0,0

提示:

2 <= n <= 105

0 <= numsi <= 1

1 <= k <= 105

0 <= maxChanges <= 105

maxChanges + sum(nums) >= k

题解:

方法:贪心 + 前缀和 + 二分查找

java 复制代码
class Solution {
    public long minimumMoves(int[] nums, int k, int maxChanges) {
        int n = nums.length;
        int[] cnt = new int[n + 1];
        long[] s = new long[n + 1];
        for (int i = 1; i <= n; ++i) {
            cnt[i] = cnt[i - 1] + nums[i - 1];
            s[i] = s[i - 1] + i * nums[i - 1];
        }
        long ans = Long.MAX_VALUE;
        for (int i = 1; i <= n; ++i) {
            long t = 0;
            int need = k - nums[i - 1];
            for (int j = i - 1; j <= i + 1; j += 2) {
                if (need > 0 && 1 <= j && j <= n && nums[j - 1] == 1) {
                    --need;
                    ++t;
                }
            }
            int c = Math.min(need, maxChanges);
            need -= c;
            t += c * 2;
            if (need <= 0) {
                ans = Math.min(ans, t);
                continue;
            }
            int l = 2, r = Math.max(i - 1, n - i);
            while (l <= r) {
                int mid = (l + r) >> 1;
                int l1 = Math.max(1, i - mid), r1 = Math.max(0, i - 2);
                int l2 = Math.min(n + 1, i + 2), r2 = Math.min(n, i + mid);
                int c1 = cnt[r1] - cnt[l1 - 1];
                int c2 = cnt[r2] - cnt[l2 - 1];
                if (c1 + c2 >= need) {
                    long t1 = 1L * c1 * i - (s[r1] - s[l1 - 1]);
                    long t2 = s[r2] - s[l2 - 1] - 1L * c2 * i;
                    ans = Math.min(ans, t + t1 + t2);
                    r = mid - 1;
                } else {
                    l = mid + 1;
                }
            }
        }
        return ans;
    }
}

5.修改矩阵

题目链接:3033. 修改矩阵

给你一个下标从 0 开始、大小为 m x n 的整数矩阵 matrix ,新建一个下标从 0 开始、名为 answer 的矩阵。使 answer 与 matrix 相等,接着将其中每个值为 -1 的元素替换为所在列的 最大 元素。

返回矩阵 answer 。

示例 1:

输入:matrix = \[1,2,-1,4,-1,6,7,8,9]

输出:\[1,2,9,4,8,6,7,8,9]

解释:上图显示了发生替换的元素(蓝色区域)。

  • 将单元格 11 中的值替换为列 1 中的最大值 8 。
  • 将单元格 02 中的值替换为列 2 中的最大值 9 。

示例 2:

输入:matrix = \[3,-1,5,2]

输出:\[3,2,5,2]

解释:上图显示了发生替换的元素(蓝色区域)。

提示:

m == matrix.length

n == matrixi.length

2 <= m, n <= 50

-1 <= matrixij <= 100

测试用例中生成的输入满足每列至少包含一个非负整数。

题解:

方法:模拟

java 复制代码
class Solution {
    public int[][] modifiedMatrix(int[][] matrix) {
        int m = matrix.length, n = matrix[0].length;
        for (int j = 0; j < n; ++j) {
            int mx = -1;
            for (int i = 0; i < m; ++i) {
                mx = Math.max(mx, matrix[i][j]);
            }
            for (int i = 0; i < m; ++i) {
                if (matrix[i][j] == -1) {
                    matrix[i][j] = mx;
                }
            }
        }
        return matrix;
    }
}

6.交替子数组计数

题目链接:3101. 交替子数组计数

给你一个

二进制数组

nums 。

如果一个

子数组

中 不存在 两个 相邻 元素的值 相同 的情况,我们称这样的子数组为 交替子数组 。

返回数组 nums 中交替子数组的数量。

示例 1:

输入: nums = 0,1,1,1

输出: 5

解释:

以下子数组是交替子数组:0111 以及 0,1

示例 2:

输入: nums = 1,0,1,0

输出: 10

解释:

数组的每个子数组都是交替子数组。可以统计在内的子数组共有 10 个。

提示:

1 <= nums.length <= 105

numsi 不是 0 就是 1 。

题解:

方法:枚举

java 复制代码
class Solution {
    public long countAlternatingSubarrays(int[] nums) {
        long ans = 1, s = 1;
        for (int i = 1; i < nums.length; ++i) {
            s = nums[i] != nums[i - 1] ? s + 1 : 1;
            ans += s;
        }
        return ans;
    }
}

7.检查操作是否合法

题目链接:1958. 检查操作是否合法

给你一个下标从 0 开始的 8 x 8 网格 board ,其中 boardrc 表示游戏棋盘上的格子 (r, c) 。棋盘上空格用 '.' 表示,白色格子用 'W' 表示,黑色格子用 'B' 表示。

游戏中每次操作步骤为:选择一个空格子,将它变成你正在执行的颜色(要么白色,要么黑色)。但是,合法 操作必须满足:涂色后这个格子是 好线段的一个端点 (好线段可以是水平的,竖直的或者是对角线)。

好线段 指的是一个包含 三个或者更多格子(包含端点格子)的线段,线段两个端点格子为 同一种颜色 ,且中间剩余格子的颜色都为 另一种颜色 (线段上不能有任何空格子)。你可以在下图找到好线段的例子:

给你两个整数 rMove 和 cMove 以及一个字符 color ,表示你正在执行操作的颜色(白或者黑),如果将格子 (rMove, cMove) 变成颜色 color 后,是一个 合法 操作,那么返回 true ,如果不是合法操作返回 false 。

示例 1:

输入:board =

\[".",".",".","B",".",".",".",".",".",".",".","W",".",".",".",".",".",".",".","W",".",".",".",".",".",".",".","W",".",".",".",".","W","B","B",".","W","W","W","B",".",".",".","B",".",".",".",".",".",".",".","B",".",".",".",".",".",".",".","W",".",".",".","."],

rMove = 4, cMove = 3, color = "B"

输出:true

解释:'.','W' 和 'B' 分别用颜色蓝色,白色和黑色表示。格子 (rMove, cMove) 用 'X' 标记。

以选中格子为端点的两个好线段在上图中用红色矩形标注出来了。

示例 2:

输入:board =

\[".",".",".",".",".",".",".",".",".","B",".",".","W",".",".",".",".",".","W",".",".",".",".",".",".",".",".","W","B",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".","B","W",".",".",".",".",".",".",".",".","W",".",".",".",".",".",".",".",".","B"],

rMove = 4, cMove = 4, color = "W"

输出:false

解释:虽然选中格子涂色后,棋盘上产生了好线段,但选中格子是作为中间格子,没有产生以选中格 子为端点的好线段。

提示:

board.length == boardr.length == 8

0 <= rMove, cMove < 8

boardrMovecMove == '.'

color 要么是 'B' 要么是 'W' 。

题解:

方法:枚举

java 复制代码
class Solution {
    public boolean checkMove(char[][] board, int rMove, int cMove, char color) {
        for (int a = -1; a <= 1; ++a) {
            for (int b = -1; b <= 1; ++b) {
                if (a == 0 && b == 0) {
                    continue;
                }
                int i = rMove, j = cMove;
                int cnt = 0;
                while (0 <= i + a && i + a < 8 && 0 <= j + b && j + b < 8) {
                    i += a;
                    j += b;
                    if (++cnt > 1 && board[i][j] == color) {
                        return true;
                    }
                    if (board[i][j] == color || board[i][j] == '.') {
                        break;
                    }
                }
            }
        }
        return false;
    }
}

下接:【题解】------ LeetCode一周小结28


相关推荐
小雨下雨的雨11 小时前
井字棋AI机器人实现详解 - Minimax算法实战-鸿蒙PC Electron框架完成
前端·人工智能·算法·华为·electron·鸿蒙
xieliyu.13 小时前
Java算法精讲:双指针(三)
java·开发语言·算法
一条小锦吕*14 小时前
基于Spring Boot + 数据可视化 + 协同过滤算法的推荐系统设计与实现(源码+论文+部署全讲解)
spring boot·算法·信息可视化
如竟没有火炬15 小时前
最大矩阵——单调栈
数据结构·python·线性代数·算法·leetcode·矩阵
8Qi816 小时前
LeetCode 1143 & 718:最长公共子序列 / 最长重复子数组
算法·leetcode·职场和发展·动态规划
绿算技术16 小时前
万卡推理集群存储选型分析:从核心架构到应用视角
大数据·科技·算法·架构
想吃火锅100517 小时前
【leetcode】1.两数之和js版
javascript·算法·leetcode
net3m3318 小时前
一阶软件低通滤波器算法
人工智能·算法
水木流年追梦18 小时前
大模型入门-大模型优化方法12-YaRN 长文本外推技术
人工智能·分布式·算法·正则表达式·prompt