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

第 96 场周赛:三维形体投影面积、救生艇、索引处的解码字符串、细分图中的可到达节点

Q1、三维形体投影面积

1、题目描述

n x n 的网格 grid 中,我们放置了一些与 x,y,z 三轴对齐的 1 x 1 x 1 立方体。

每个值 v = grid[i][j] 表示有一列 v 个正方体叠放在格子 (i, j) 上。

现在,我们查看这些立方体在 xyyzzx 平面上的投影

投影 就像影子,将 三维 形体映射到一个 二维 平面上。从顶部、前面和侧面看立方体时,我们会看到 “影子”。

返回 所有三个投影的总面积

示例 1:

img
输入:[[1,2],[3,4]]
输出:17
解释:这里有该形体在三个轴对齐平面上的三个投影(“阴影部分”)。

示例 2:

输入:grid = [[2]]
输出:5

示例 3:

输入:[[1,0],[0,2]]
输出:8

提示:

  • n == grid.length == grid[i].length
  • 1 <= n <= 50
  • 0 <= grid[i][j] <= 50
2、解题思路
  1. xy 平面投影

    • 每个格子只要有立方体(grid[i][j] > 0),就贡献 1 的面积。
    • 所以 xyArea 就是所有 grid[i][j] > 0 的格子数。
  2. yz 平面投影

    • 对于每一列 j,取该列所有行的最大值 max(grid[0][j], grid[1][j], ..., grid[n-1][j])
    • yzArea 是所有列的最大值之和。
  3. zx 平面投影

    • 对于每一行 i,取该行所有列的最大值 max(grid[i][0], grid[i][1], ..., grid[i][n-1])
    • zxArea 是所有行的最大值之和。
3、代码实现
C++
class Solution {
public:int projectionArea(vector<vector<int>>& grid) {int n = grid.size();int xyArea = 0, yzArea = 0, zxArea = 0;for (int i = 0; i < n; ++i) {int yzHeight = 0, zxHeight = 0;for (int j = 0; j < n; ++j) {xyArea += grid[i][j] > 0 ? 1 : 0;     // xy 投影: 每个格子贡献 1yzHeight = max(yzHeight, grid[j][i]); // yz 投影: 每列最大值zxHeight = max(zxHeight, grid[i][j]); // zx 投影: 每行最大值}yzArea += yzHeight;zxArea += zxHeight;}return xyArea + yzArea + zxArea;}
};
Java
class Solution {public int projectionArea(int[][] grid) {int n = grid.length;int xyArea = 0, yzArea = 0, zxArea = 0;for (int i = 0; i < n; i++) {int yzHeight = 0, zxHeight = 0;for (int j = 0; j < n; j++) {xyArea += grid[i][j] > 0 ? 1 : 0; // xy投影yzHeight = Math.max(yzHeight, grid[j][i]); // yz投影zxHeight = Math.max(zxHeight, grid[i][j]); // zx投影}yzArea += yzHeight;zxArea += zxHeight;}return xyArea + yzArea + zxArea;}
}
Python
class Solution:def projectionArea(self, grid: List[List[int]]) -> int:n = len(grid)xyArea = sum(1 for i in range(n) for j in range(n) if grid[i][j] > 0)yzArea = sum(max(grid[i][j] for i in range(n)) for j in range(n))zxArea = sum(max(row) for row in grid)return xyArea + yzArea + zxArea
4、复杂度分析
  • 时间复杂度O(n^2),需要遍历整个网格两次(行和列)。
  • 空间复杂度O(1),仅需常数空间存储中间变量。

Q2、救生艇

1、题目描述

给定数组 peoplepeople[i]表示第 i 个人的体重 ,船的数量不限,每艘船可以承载的最大重量为 limit

每艘船最多可同时载两人,但条件是这些人的重量之和最多为 limit

返回 承载所有人所需的最小船数

示例 1:

输入:people = [1,2], limit = 3
输出:1
解释:1 艘船载 (1, 2)

示例 2:

输入:people = [3,2,2,1], limit = 3
输出:3
解释:3 艘船分别载 (1, 2), (2) 和 (3)

示例 3:

输入:people = [3,5,3,4], limit = 5
输出:4
解释:4 艘船分别载 (3), (3), (4), (5)

提示:

  • 1 <= people.length <= 5 * 104
  • 1 <= people[i] <= limit <= 3 * 104
2、解题思路
  1. 贪心算法

    • 将数组排序,这样我们可以尝试将最轻和最重的人配对。
    • 如果最轻和最重的人可以一起乘船(people[light] + people[heavy] <= limit),则配对成功,船数加一,双指针移动。
    • 如果无法配对,则最重的人单独乘船,船数加一,右指针移动。
3、代码实现
C++
class Solution {
public:int numRescueBoats(vector<int>& people, int limit) {int ans = 0;sort(people.begin(), people.end()); // 排序int light = 0, heavy = people.size() - 1;while (light <= heavy) {if (people[light] + people[heavy] <= limit) {// 可以配对++light;--heavy;} else // 无法配对, 最重的人单独乘船{--heavy;}++ans; // 船数 +1}return ans;}
};
Java
class Solution {public int numRescueBoats(int[] people, int limit) {int ans = 0;Arrays.sort(people); // 排序int light = 0, heavy = people.length - 1;while (light <= heavy) {if (people[light] + people[heavy] <= limit) { // 可以配对light++;heavy--;} else { // 无法配对,最重的人单独乘船heavy--;}ans++; // 船数加一}return ans;}
}
Python
class Solution:def numRescueBoats(self, people: List[int], limit: int) -> int:people.sort() # 排序light, heavy = 0, len(people) - 1ans = 0while light <= heavy:if people[light] + people[heavy] <= limit: # 可以配对light += 1heavy -= 1else: # 无法配对,最重的人单独乘船heavy -= 1ans += 1 # 船数加一return ans
4、复杂度分析
  • 时间复杂度O(n log n),排序的时间复杂度。
  • 空间复杂度O(1),仅需常数空间。

Q3、索引处的解码字符串

1、题目描述

给定一个编码字符串 s 。请你找出 解码字符串 并将其写入磁带。解码时,从编码字符串中 每次读取一个字符 ,并采取以下步骤:

  • 如果所读的字符是字母,则将该字母写在磁带上。
  • 如果所读的字符是数字(例如 d),则整个当前磁带总共会被重复写 d-1 次。

现在,对于给定的编码字符串 s 和索引 k,查找并返回解码字符串中的第 k 个字母。

示例 1:

输入:s = "leet2code3", k = 10
输出:"o"
解释:
解码后的字符串为 "leetleetcodeleetleetcodeleetleetcode"。
字符串中的第 10 个字母是 "o"。

示例 2:

输入:s = "ha22", k = 5
输出:"h"
解释:
解码后的字符串为 "hahahaha"。第 5 个字母是 "h"。

示例 3:

输入:s = "a2345678999999999999999", k = 1
输出:"a"
解释:
解码后的字符串为 "a" 重复 8301530446056247680 次。第 1 个字母是 "a"。

提示:

  • 2 <= s.length <= 100
  • s 只包含小写字母与数字 29
  • s 以字母开头。
  • 1 <= k <= 109
  • 题目保证 k 小于或等于解码字符串的长度。
  • 解码后的字符串保证少于 263 个字母。
2、解题思路
  1. 正向计算总长度

    • 遍历字符串 s,计算解码后的字符串总长度 size
    • 遇到字母时,size 加 1。
    • 遇到数字时,size 乘以该数字。
  2. 逆向定位第 k 个字母

    • 从后向前遍历字符串 s,逐步缩小 sizek 的范围。
    • k %= size,如果 k == 0 且当前字符是字母,则返回该字母。
    • 如果当前字符是数字,则 size /= d(逆向操作)。
    • 否则 size--(逆向操作)。
3、代码实现
C++
class Solution {
public:string decodeAtIndex(string s, int k) {long size = 0;int n = s.size();// 计算解码后的字符串总长度for (int i = 0; i < n; ++i) {if (isdigit(s[i])) {size *= s[i] - '0';} else {++size;}}// 逆向定位第 k 个字母for (int i = n - 1; i >= 0; --i) {k %= size;if (k == 0 && isalpha(s[i])) {return string(1, s[i]);}if (isdigit(s[i])) {size /= s[i] - '0';} else {--size;}}return ""; // 不会执行, 题目保证 k 有效}
};
Java
class Solution {public String decodeAtIndex(String s, int k) {long size = 0;int n = s.length();// 计算解码后的字符串总长度for (int i = 0; i < n; ++i) {char c = s.charAt(i);if (Character.isDigit(c))size *= c - '0';elsesize++;}// 逆向定位第 k 个字母for (int i = n - 1; i >= 0; --i) {char c = s.charAt(i);k %= size;if (k == 0 && Character.isLetter(c))return String.valueOf(c);if (Character.isDigit(c))size /= c - '0';elsesize--;}return ""; // 不会执行,题目保证 k 有效}
}
Python
class Solution:def decodeAtIndex(self, s: str, k: int) -> str:size = 0n = len(s)# 计算解码后的字符串总长度for c in s:if c.isdigit():size *= int(c)else:size += 1# 逆向定位第 k 个字母for c in reversed(s):k %= sizeif k == 0 and c.isalpha():return cif c.isdigit():size //= int(c)else:size -= 1return ""  # 不会执行,题目保证 k 有效
4、复杂度分析
  • 时间复杂度O(n),其中 n 是字符串 s 的长度。
  • 空间复杂度O(1),仅使用常数空间。

Q4、细分图中的可到达节点

1、题目描述

给你一个无向图(原始图),图中有 n 个节点,编号从 0n - 1 。你决定将图中的每条边 细分 为一条节点链,每条边之间的新节点数各不相同。

图用由边组成的二维数组 edges 表示,其中 edges[i] = [ui, vi, cnti] 表示原始图中节点 uivi 之间存在一条边,cnti 是将边 细分 后的新节点总数。注意,cnti == 0 表示边不可细分。

细分[ui, vi] ,需要将其替换为 (cnti + 1) 条新边,和 cnti 个新节点。新节点为 x1, x2, …, xcnti ,新边为 [ui, x1], [x1, x2], [x2, x3], …, [xcnti-1, xcnti], [xcnti, vi]

现在得到一个 新的细分图 ,请你计算从节点 0 出发,可以到达多少个节点?如果节点间距离是 maxMoves 或更少,则视为 可以到达

给你原始图和 maxMoves ,返回 新的细分图中从节点 0 出发 *可到达的节点数*

示例 1:

img
输入:edges = [[0,1,10],[0,2,1],[1,2,2]], maxMoves = 6, n = 3
输出:13
解释:边的细分情况如上图所示。
可以到达的节点已经用黄色标注出来。

示例 2:

输入:edges = [[0,1,4],[1,2,6],[0,2,8],[1,3,1]], maxMoves = 10, n = 4
输出:23

示例 3:

输入:edges = [[1,2,4],[1,4,5],[1,3,1],[2,3,4],[3,4,5]], maxMoves = 17, n = 5
输出:1
解释:节点 0 与图的其余部分没有连通,所以只有节点 0 可以到达。

提示:

  • 0 <= edges.length <= min(n * (n - 1) / 2, 104)
  • edges[i].length == 3
  • 0 <= ui < vi < n
  • 图中 不存在平行边
  • 0 <= cnti <= 104
  • 0 <= maxMoves <= 109
  • 1 <= n <= 3000
2、解题思路
  1. 构建邻接表
    • 将原始图的每条边及其细分节点数存入邻接表。
  2. Dijkstra算法
    • 使用优先队列(最小堆)来遍历图,计算从节点0到其他节点的最短路径。
    • 在遍历过程中,记录每个节点是否被访问过,以及从节点0到该节点的最短距离。
  3. 统计可到达节点
    • 原始节点:如果从节点0到该节点的最短距离不超过 maxMoves,则该节点可到达。
    • 细分节点:对于每条边 [u, v],计算从 uv 出发可以覆盖的细分节点数,取最小值。
3、代码实现
C++
class Solution {
private:// 自定义函数:将两个节点的编号编码为一个唯一的整数,// 用于在哈希表中存储边的使用情况int encode(int u, int v, int n) { return u * n + v; }public:int reachableNodes(vector<vector<int>>& edges, int maxMoves, int n) {// 构建邻接表,存储图的边和细分节点数vector<vector<pair<int, int>>> adList(n);for (auto& edge : edges) {int u = edge[0], v = edge[1], nodes = edge[2];// 无向图,双向存储adList[u].emplace_back(v, nodes);adList[v].emplace_back(u, nodes);}// used: 记录每条边已经覆盖的细分节点数unordered_map<int, int> used;// visited: 记录已经访问过的原始节点unordered_set<int> visited;// reachableNodes: 统计可到达的节点数int reachableNodes = 0;// 优先队列 (最小堆), 用于 Dijkstra 算法, 存储 (从节点0到当前节点的步数,// 当前节点编号)priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;pq.emplace(0, 0); // 初始状态: 步数 0, 节点 0// Dijkstra 算法遍历图while (!pq.empty() && pq.top().first <= maxMoves) {auto [step, u] = pq.top();pq.pop();// 如果节点已经访问过,跳过if (visited.count(u)) {continue;}// 标记节点为已访问visited.emplace(u);// 可到达的原始节点数 +1reachableNodes++;// 遍历当前节点的所有邻居for (auto [v, nodes] : adList[u]) {// 如果从 u 到 v 的路径 (包括细分节点) 总步数不超过 maxMoves, 且 v 未被访问if (nodes + step + 1 <= maxMoves && !visited.count(v)) {// 将 v 加入优先队列, 步数为 u 的步数 + 细分节点数 + 1 (原始边算一步)pq.emplace(nodes + step + 1, v);}// 记录从 u 到 v 这条边上覆盖的细分节点数, 最多覆盖 maxMoves - step 个 (剩余步数限制)used[encode(u, v, n)] = min(nodes, maxMoves - step);}}// 统计所有边上的细分节点覆盖情况for (auto& edge : edges) {int u = edge[0], v = edge[1], nodes = edge[2];// 计算这条边两端节点覆盖的细分节点数之和, 但不能超过总细分节点数reachableNodes += min(nodes, used[encode(u, v, n)] + used[encode(v, u, n)]);}return reachableNodes;}
};
Java
class Solution {public int reachableNodes(int[][] edges, int maxMoves, int n) {// 邻接表Map<Integer, Integer>[] adList = new Map[n];for (int i = 0; i < n; i++) {adList[i] = new HashMap<>();}for (int[] edge : edges) {int u = edge[0], v = edge[1], nodes = edge[2];adList[u].put(v, nodes);adList[v].put(u, nodes);}// 记录每条边已覆盖的细分节点数Map<Integer, Integer> used = new HashMap<>();// 记录已访问的原始节点Set<Integer> visited = new HashSet<>();int reachableNodes = 0;// 优先队列(最小堆)PriorityQueue<int[]> pq = new PriorityQueue<>((a, b) -> a[0] - b[0]);pq.offer(new int[] { 0, 0 });// Dijkstra 算法while (!pq.isEmpty() && pq.peek()[0] <= maxMoves) {int[] curr = pq.poll();int step = curr[0], u = curr[1];if (visited.contains(u)) {continue;}visited.add(u);reachableNodes++;for (Map.Entry<Integer, Integer> entry : adList[u].entrySet()) {int v = entry.getKey(), nodes = entry.getValue();if (nodes + step + 1 <= maxMoves && !visited.contains(v)) {pq.offer(new int[] { nodes + step + 1, v });}used.put(encode(u, v, n), Math.min(nodes, maxMoves - step));}}// 统计细分节点for (int[] edge : edges) {int u = edge[0], v = edge[1], nodes = edge[2];reachableNodes += Math.min(nodes, used.getOrDefault(encode(u, v, n), 0) + used.getOrDefault(encode(v, u, n), 0));}return reachableNodes;}// 编码函数private int encode(int u, int v, int n) {return u * n + v;}
}
Python
class Solution:def reachableNodes(self, edges: List[List[int]], maxMoves: int, n: int) -> int:# 邻接表adList = [{} for _ in range(n)]for u, v, nodes in edges:adList[u][v] = nodesadList[v][u] = nodesused = {}visited = set()reachableNodes = 0heap = [(0, 0)]while heap and heap[0][0] <= maxMoves:step, u = heapq.heappop(heap)if u in visited:continuevisited.add(u)reachableNodes += 1for v, nodes in adList[u].items():if nodes + step + 1 <= maxMoves and v not in visited:heapq.heappush(heap, (nodes + step + 1, v))used[(u, v)] = min(nodes, maxMoves - step)# 统计细分节点for u, v, nodes in edges:reachableNodes += min(nodes, used.get((u, v), 0) + used.get((v, u), 0))return reachableNodes
4、复杂度分析
  • 时间复杂度O(E log V),其中 E 是边的数量,V 是节点数量。Dijkstra算法的时间复杂度为 O(E log V)
  • 空间复杂度O(V + E),用于存储邻接表和优先队列。



http://www.dtcms.com/a/477555.html

相关文章:

  • 网站建设宁夏凤凰云什么是电子商务系统
  • 用php做电子商务网站微信做商城网站
  • 【LeetCode】146. LRU 缓存
  • Linux Cgroup与Device Whitelist详解
  • 恶意代码防范技术与原理(二)
  • Facebook广告投放:地域定向流量不精准?x个优化指南
  • 【Linux指令 (三)】从理解到熟悉:探索Linux底层逻辑与指令的高效之道,理解Linux系统理论核心概念与基础指令
  • 2025年10月实时最新获取地图边界数据方法,省市区县街道多级联动【文末附实时geoJson数据下载】
  • 基于单片机的燃气热水器智能控制系统设计
  • 江苏省建设厅网站怎么登不上html网页代码编辑器
  • 云服务器怎么架设网站wordpress删除月份归档
  • go语言返回值 于defer的特殊原理
  • 《线性代数》---大学数学基础课程
  • 【Go】---流程控制语句
  • Go小白学习路线
  • CMP (类Cloudera) CDP7.3(400次编译)在华为鲲鹏Aarch64(ARM)信创环境中的性能测试过程及命令
  • [GO]什么是热重载,如何使用Air工具
  • 福州网站建设公司哪个好济南工程建设验收公示网
  • 百度爱采购服务商查询丽水网站建设seo
  • 小黑享受思考心流: 132. 分割回文串 II
  • java求职学习day38
  • Golang—channel
  • 推三返一链动模式图解
  • 【人工智能与机器人研究】一种库坝系统水下成像探查有缆机器人系统设计模式
  • Qt---setAttribute设置控件或窗口的内部属性
  • 储能的“胜负手”:容量、策略与经济性如何平衡?
  • 蓝桥杯出局,少儿编程的价值祛魅时刻?
  • TensorFlow2 Python深度学习 - 使用TensorBoard可视化数据
  • wordpress忘记了密码忘记网站优化文章
  • 怎么看网站用哪个系统做的泰安集团网站建设方案