力扣第 102 场双周赛
题目链接:https://leetcode.cn/contest/biweekly-contest-102/
# T1. 查询网格图中每一列的宽度
链接:https://leetcode.cn/problems/find-the-width-of-columns-of-a-grid/
# 代码
class Solution { | |
public int[] findColumnWidth(int[][] grid) { | |
int m = grid.length; | |
int n = grid[0].length; | |
int[] ans = new int[n]; | |
for (int i = 0; i < n; ++i) { | |
int max = 0; | |
for (int j = 0; j < m; ++j) { | |
int abs = Math.abs(grid[j][i]); | |
int l = len(abs); | |
l = grid[j][i] < 0 ? l + 1 : l; | |
max = Math.max(l, max); | |
} | |
ans[i] = max; | |
} | |
return ans; | |
} | |
private int len(int k) { | |
if (k == 0) return 1; | |
int ret = 0; | |
while (k > 0) { | |
++ret; | |
k /= 10; | |
} | |
return ret; | |
} | |
} |
# T2. 一个数组所有前缀的分数
链接:https://leetcode.cn/problems/find-the-score-of-all-prefixes-of-an-array/
# 思路
根据题意模拟即可
# 提交结果
# 代码
class Solution { | |
public long[] findPrefixScore(int[] nums) { | |
int n = nums.length; | |
long[] ans = new long[n]; | |
long max = 0; | |
for (int i = 0; i < n; ++i) { | |
max = Math.max(nums[i], max); | |
ans[i] = max + nums[i]; | |
if (i > 0) { | |
ans[i] += ans[i - 1]; | |
} | |
} | |
return ans; | |
} | |
} |
# T3. 二叉树的堂兄弟节点 II
链接:https://leetcode.cn/problems/cousins-in-binary-tree-ii/
# 解题思路
二叉树层序遍历:
- 记录每个节点的直接父亲节点
- 根据父亲节点进行分组求和,最后更新左右子节点的值即可
具体看代码
# 提交结果
# 代码
class Solution { | |
public TreeNode replaceValueInTree(TreeNode root) { | |
if (root == null) return null; | |
Queue<TreeNode[]> que = new ArrayDeque<>(); | |
root.val = 0; | |
if (root.left != null) { | |
que.offer(new TreeNode[] {root, root.left}); | |
} | |
if (root.right != null) { | |
que.offer(new TreeNode[] {root, root.right}); | |
} | |
while (!que.isEmpty()) { | |
Map<TreeNode, Integer> sumMap = new HashMap<>(); | |
int sum = 0; | |
for (int i = que.size(); i > 0; --i) { | |
TreeNode[] cur = que.poll(); | |
sumMap.put(cur[0], sumMap.getOrDefault(cur[0], 0) + cur[1].val); | |
sum += cur[1].val; | |
if (cur[1].left != null) { | |
que.offer(new TreeNode[] {cur[1], cur[1].left}); | |
} | |
if (cur[1].right != null) { | |
que.offer(new TreeNode[] {cur[1], cur[1].right}); | |
} | |
} | |
for (Map.Entry<TreeNode, Integer> e : sumMap.entrySet()) { | |
TreeNode node = e.getKey(); | |
int value = e.getValue(); | |
int v = sum - value; | |
if (node.left != null) { | |
node.left.val = v; | |
} | |
if (node.right != null) { | |
node.right.val = v; | |
} | |
} | |
} | |
return root; | |
} | |
} |
# 优化
不用每次记录当前节点的父节点,而是每次遍历一层时,更新下一层的节点值即可。
class Solution { | |
public TreeNode replaceValueInTree(TreeNode root) { | |
// 在 parent 层,处理 children 层 | |
if (root == null) return null; | |
Queue<TreeNode> que = new ArrayDeque<>(); | |
// 根节点直接赋值 0 | |
root.val = 0; | |
que.offer(root); | |
while (!que.isEmpty()) { | |
Map<TreeNode, Integer> sumMap = new HashMap<>(); | |
// 记录所有父节点的所有子节点值的和 | |
int sum = 0; | |
for (TreeNode p : que) { | |
sum += p.left != null ? p.left.val : 0; | |
sum += p.right != null ? p.right.val : 0; | |
} | |
// 更新父节点的子节点的值 | |
for (int i = que.size(); i > 0; --i) { | |
TreeNode cur = que.poll(); | |
int cs = cur.left != null ? cur.left.val : 0; | |
cs += cur.right != null ? cur.right.val : 0; | |
if (cur.left != null) { | |
cur.left.val = sum - cs; | |
que.offer(cur.left); | |
} | |
if (cur.right != null) { | |
cur.right.val = sum - cs; | |
que.offer(cur.right); | |
} | |
} | |
} | |
return root; | |
} | |
} |
# T4. 设计可以求最短路径的图类
链接:https://leetcode.cn/problems/design-graph-with-shortest-path-calculator/
# 解题思路
典型 Dijkstra 算法应用
# 提交结果
# 代码
class Graph { | |
// 边的权值:es [i][j] 表示 i -> j,有一条权值 es [i][j] 的有向边 | |
//es [i][j]=Integer.MAX_VALUE 表示 i -> j 为不可达 | |
int[][] es; | |
// 节点总数 | |
int nodeCnt; | |
public Graph(int n, int[][] edges) { | |
es = new int[n][n]; | |
this.nodeCnt = n; | |
// 初始化所有点相互之间的距离 | |
for (int i = 0; i < n; ++i) { | |
Arrays.fill(es[i], Integer.MAX_VALUE); | |
} | |
for (int[] e : edges) { | |
es[e[0]][e[1]] = e[2]; | |
} | |
} | |
public void addEdge(int[] edge) { | |
es[edge[0]][edge[1]] = edge[2]; | |
} | |
public int shortestPath(int node1, int node2) { | |
if (node1 == node2) return 0; | |
int[] dis = new int[nodeCnt]; | |
boolean[] vis = new boolean[nodeCnt]; | |
// 加入集合 | |
vis[node1] = true; | |
// 更新 node1 -> 其他节点的直接距离 | |
for (int i = 0; i < nodeCnt; ++i) { | |
dis[i] = es[node1][i]; | |
} | |
// 最多松弛 nodeCnt - 1 次 | |
for (int i = 1; i < nodeCnt; ++i) { | |
// 到下一个最短路径的点 | |
int nxt = -1; | |
// 到下一个点的最短距离 | |
int minDis = Integer.MAX_VALUE; | |
for (int j = 0; j < nodeCnt; ++j) { | |
if (!vis[j] && dis[j] < minDis) { | |
nxt = j; | |
minDis = dis[j]; | |
} | |
} | |
// 没有多余的到可达点,直接退出 | |
// 优化:已经到达终点 | |
if (nxt == -1 || nxt == node2) break; | |
// 找到一个点 | |
vis[nxt] = true; | |
// 松弛操作,通过 nxt 节点 | |
for (int j = 0; j < nodeCnt; j++) { | |
if (!vis[j] // 未加入集合 | |
&& es[nxt][j] != Integer.MAX_VALUE // 可达 | |
&& minDis + es[nxt][j] < dis[j]) { // 可松弛,更新最小值 | |
dis[j] = minDis + es[nxt][j]; | |
} | |
} | |
} | |
return dis[node2] == Integer.MAX_VALUE ? -1 : dis[node2]; | |
} | |
} | |
/** | |
* Your Graph object will be instantiated and called as such: | |
* Graph obj = new Graph(n, edges); | |
* obj.addEdge(edge); | |
* int param_2 = obj.shortestPath(node1,node2); | |
*/ |