diff --git a/solution/2300-2399/2300.Successful Pairs of Spells and Potions/README.md b/solution/2300-2399/2300.Successful Pairs of Spells and Potions/README.md index b272cf82cf7d7..18ebe97f9298b 100644 --- a/solution/2300-2399/2300.Successful Pairs of Spells and Potions/README.md +++ b/solution/2300-2399/2300.Successful Pairs of Spells and Potions/README.md @@ -54,7 +54,7 @@ **方法一:排序 + 二分查找** -我们可以对药水数组进行排序,然后遍历咒语数组,对于每个咒语,利用二分查找找到第一个大于等于 `success / v` 的药水,下标记为 $i$,那么药水的长度减去 $i$ 即为能跟该咒语成功组合的药水数目。 +我们可以对药水数组进行排序,然后遍历咒语数组,对于每个咒语 $v$,利用二分查找找到第一个大于等于 $\frac{success}{v}$ 的药水,下标记为 $i$,那么药水的长度减去 $i$ 即为能跟该咒语成功组合的药水数目。 时间复杂度 $O((m + n) \times \log m)$,空间复杂度 $O(\log n)$。其中 $m$ 和 $n$ 分别为药水数组和咒语数组的长度。 diff --git a/solution/2900-2999/2920.Maximum Points After Collecting Coins From All Nodes/README.md b/solution/2900-2999/2920.Maximum Points After Collecting Coins From All Nodes/README.md index 58bf576baeb48..72965be7450c5 100644 --- a/solution/2900-2999/2920.Maximum Points After Collecting Coins From All Nodes/README.md +++ b/solution/2900-2999/2920.Maximum Points After Collecting Coins From All Nodes/README.md @@ -61,6 +61,24 @@ +**方法一:记忆化搜索** + +我们先根据题目给定的边构建图 $g$,其中 $g[i]$ 表示节点 $i$ 的所有邻接节点。然后我们可以使用记忆化搜索的方法求解本题。 + +我们设计一个函数 $dfs(i, fa, j)$,表示当前节点为 $i$,父节点为 $fa$,当前节点的金币数需要右移 $j$ 位,所能获得的最大积分。 + +函数 $dfs(i, fa, j)$ 的执行过程如下: + +如果我们使用第一种方法收集当前节点的金币,那么当前节点的积分为 $(coins[i] >> j) - k$,然后我们遍历当前节点的所有邻接节点 $c$,如果 $c$ 不等于 $fa$,那么我们将 $dfs(c, i, j)$ 的结果累加到当前节点的积分中。 + +如果我们使用第二种方法收集当前节点的金币,那么当前节点的积分为 $coins[i] >> (j + 1)$,然后我们遍历当前节点的所有邻接节点 $c$,如果 $c$ 不等于 $fa$,那么我们将 $dfs(c, i, j + 1)$ 的结果累加到当前节点的积分中。注意,由于题目中给定的 $coins[i]$ 最大值为 $10^4$,因此我们最多只能右移 $14$ 位,就使得 $coins[i] >> (j + 1)$ 的值为 $0$。 + +最后,我们返回当前节点使用两种方法中能获得的最大积分。 + +为了避免重复计算,我们使用记忆化搜索的方法,将 $dfs(i, fa, j)$ 的结果存储到 $f[i][j]$ 中,其中 $f[i][j]$ 表示当前节点为 $i$,父节点为 $fa$,当前节点的金币数需要右移 $j$ 位,所能获得的最大积分。 + +时间复杂度 $O(n \times \log M)$,空间复杂度 $O(n \times \log M)$。其中 $M$ 表示 $coins[i]$ 的最大值。 + ### **Python3** @@ -68,7 +86,27 @@ ```python - +class Solution: + def maximumPoints(self, edges: List[List[int]], coins: List[int], k: int) -> int: + @cache + def dfs(i: int, fa: int, j: int) -> int: + a = (coins[i] >> j) - k + b = coins[i] >> (j + 1) + for c in g[i]: + if c != fa: + a += dfs(c, i, j) + if j < 14: + b += dfs(c, i, j + 1) + return max(a, b) + + n = len(coins) + g = [[] for _ in range(n)] + for a, b in edges: + g[a].append(b) + g[b].append(a) + ans = dfs(0, -1, 0) + dfs.cache_clear() + return ans ``` ### **Java** @@ -76,19 +114,151 @@ ```java - +class Solution { + private int k; + private int[] coins; + private Integer[][] f; + private List[] g; + + public int maximumPoints(int[][] edges, int[] coins, int k) { + this.k = k; + this.coins = coins; + int n = coins.length; + f = new Integer[n][15]; + g = new List[n]; + Arrays.setAll(g, i -> new ArrayList<>()); + for (var e : edges) { + int a = e[0], b = e[1]; + g[a].add(b); + g[b].add(a); + } + return dfs(0, -1, 0); + } + + private int dfs(int i, int fa, int j) { + if (f[i][j] != null) { + return f[i][j]; + } + int a = (coins[i] >> j) - k; + int b = coins[i] >> (j + 1); + for (int c : g[i]) { + if (c != fa) { + a += dfs(c, i, j); + if (j < 14) { + b += dfs(c, i, j + 1); + } + } + } + return f[i][j] = Math.max(a, b); + } +} ``` ### **C++** ```cpp - +class Solution { +public: + int maximumPoints(vector>& edges, vector& coins, int k) { + int n = coins.size(); + int f[n][15]; + memset(f, -1, sizeof(f)); + vector g[n]; + for (auto& e : edges) { + int a = e[0], b = e[1]; + g[a].emplace_back(b); + g[b].emplace_back(a); + } + function dfs = [&](int i, int fa, int j) { + if (f[i][j] != -1) { + return f[i][j]; + } + int a = (coins[i] >> j) - k; + int b = coins[i] >> (j + 1); + for (int c : g[i]) { + if (c != fa) { + a += dfs(c, i, j); + if (j < 14) { + b += dfs(c, i, j + 1); + } + } + } + return f[i][j] = max(a, b); + }; + return dfs(0, -1, 0); + } +}; ``` ### **Go** ```go +func maximumPoints(edges [][]int, coins []int, k int) int { + n := len(coins) + f := make([][]int, n) + for i := range f { + f[i] = make([]int, 15) + for j := range f[i] { + f[i][j] = -1 + } + } + g := make([][]int, n) + for _, e := range edges { + a, b := e[0], e[1] + g[a] = append(g[a], b) + g[b] = append(g[b], a) + } + var dfs func(int, int, int) int + dfs = func(i, fa, j int) int { + if f[i][j] != -1 { + return f[i][j] + } + a := (coins[i] >> j) - k + b := coins[i] >> (j + 1) + for _, c := range g[i] { + if c != fa { + a += dfs(c, i, j) + if j < 14 { + b += dfs(c, i, j+1) + } + } + } + f[i][j] = max(a, b) + return f[i][j] + } + return dfs(0, -1, 0) +} +``` +### **TypeScript** + +```ts +function maximumPoints(edges: number[][], coins: number[], k: number): number { + const n = coins.length; + const f: number[][] = Array.from({ length: n }, () => Array(15).fill(-1)); + const g: number[][] = Array.from({ length: n }, () => []); + for (const [a, b] of edges) { + g[a].push(b); + g[b].push(a); + } + const dfs = (i: number, fa: number, j: number): number => { + if (f[i][j] !== -1) { + return f[i][j]; + } + let a = (coins[i] >> j) - k; + let b = coins[i] >> (j + 1); + for (const c of g[i]) { + if (c !== fa) { + a += dfs(c, i, j); + if (j < 14) { + b += dfs(c, i, j + 1); + } + } + } + return (f[i][j] = Math.max(a, b)); + }; + return dfs(0, -1, 0); +} ``` ### **...** diff --git a/solution/2900-2999/2920.Maximum Points After Collecting Coins From All Nodes/README_EN.md b/solution/2900-2999/2920.Maximum Points After Collecting Coins From All Nodes/README_EN.md index c639f60947af1..4490c9c61f555 100644 --- a/solution/2900-2999/2920.Maximum Points After Collecting Coins From All Nodes/README_EN.md +++ b/solution/2900-2999/2920.Maximum Points After Collecting Coins From All Nodes/README_EN.md @@ -55,30 +55,200 @@ Coins will be collected from all the nodes using the first way. Therefore, total ## Solutions +**Solution 1: Memoization Search** + +First, we construct a graph $g$ based on the edges given in the problem, where $g[i]$ represents all adjacent nodes of node $i$. Then we can use the method of memoization search to solve this problem. + +We design a function $dfs(i, fa, j)$, which represents that the current node is $i$, the parent node is $fa$, the number of gold coins of the current node needs to be shifted to the right by $j$ bits, and the maximum score that can be obtained. + +The execution process of the function $dfs(i, fa, j)$ is as follows: + +If we use the first method to collect the gold coins of the current node, then the score of the current node is $(coins[i] >> j) - k$. Then we traverse all the adjacent nodes $c$ of the current node. If $c$ is not equal to $fa$, then we add the result of $dfs(c, i, j)$ to the score of the current node. + +If we use the second method to collect the gold coins of the current node, then the score of the current node is $coins[i] >> (j + 1)$. Then we traverse all the adjacent nodes $c$ of the current node. If $c$ is not equal to $fa$, then we add the result of $dfs(c, i, j + 1)$ to the score of the current node. Note that since the maximum value of $coins[i]$ given in the problem is $10^4$, we can only shift to the right by at most $14$ bits, so that the value of $coins[i] >> (j + 1)$ is $0$. + +Finally, we return the maximum score that can be obtained by using the two methods at the current node. + +In order to avoid repeated calculations, we use the method of memoization search and store the result of $dfs(i, fa, j)$ in $f[i][j]$, where $f[i][j]$ represents that the current node is $i$, the parent node is $fa$, the number of gold coins of the current node needs to be shifted to the right by $j$ bits, and the maximum score that can be obtained. + +The time complexity is $O(n \times \log M)$, and the space complexity is $O(n \times \log M)$. Where $M$ represents the maximum value of $coins[i]$. + ### **Python3** ```python +class Solution: + def maximumPoints(self, edges: List[List[int]], coins: List[int], k: int) -> int: + @cache + def dfs(i: int, fa: int, j: int) -> int: + a = (coins[i] >> j) - k + b = coins[i] >> (j + 1) + for c in g[i]: + if c != fa: + a += dfs(c, i, j) + if j < 14: + b += dfs(c, i, j + 1) + return max(a, b) + n = len(coins) + g = [[] for _ in range(n)] + for a, b in edges: + g[a].append(b) + g[b].append(a) + ans = dfs(0, -1, 0) + dfs.cache_clear() + return ans ``` ### **Java** ```java +class Solution { + private int k; + private int[] coins; + private Integer[][] f; + private List[] g; + + public int maximumPoints(int[][] edges, int[] coins, int k) { + this.k = k; + this.coins = coins; + int n = coins.length; + f = new Integer[n][15]; + g = new List[n]; + Arrays.setAll(g, i -> new ArrayList<>()); + for (var e : edges) { + int a = e[0], b = e[1]; + g[a].add(b); + g[b].add(a); + } + return dfs(0, -1, 0); + } + private int dfs(int i, int fa, int j) { + if (f[i][j] != null) { + return f[i][j]; + } + int a = (coins[i] >> j) - k; + int b = coins[i] >> (j + 1); + for (int c : g[i]) { + if (c != fa) { + a += dfs(c, i, j); + if (j < 14) { + b += dfs(c, i, j + 1); + } + } + } + return f[i][j] = Math.max(a, b); + } +} ``` ### **C++** ```cpp - +class Solution { +public: + int maximumPoints(vector>& edges, vector& coins, int k) { + int n = coins.size(); + int f[n][15]; + memset(f, -1, sizeof(f)); + vector g[n]; + for (auto& e : edges) { + int a = e[0], b = e[1]; + g[a].emplace_back(b); + g[b].emplace_back(a); + } + function dfs = [&](int i, int fa, int j) { + if (f[i][j] != -1) { + return f[i][j]; + } + int a = (coins[i] >> j) - k; + int b = coins[i] >> (j + 1); + for (int c : g[i]) { + if (c != fa) { + a += dfs(c, i, j); + if (j < 14) { + b += dfs(c, i, j + 1); + } + } + } + return f[i][j] = max(a, b); + }; + return dfs(0, -1, 0); + } +}; ``` ### **Go** ```go +func maximumPoints(edges [][]int, coins []int, k int) int { + n := len(coins) + f := make([][]int, n) + for i := range f { + f[i] = make([]int, 15) + for j := range f[i] { + f[i][j] = -1 + } + } + g := make([][]int, n) + for _, e := range edges { + a, b := e[0], e[1] + g[a] = append(g[a], b) + g[b] = append(g[b], a) + } + var dfs func(int, int, int) int + dfs = func(i, fa, j int) int { + if f[i][j] != -1 { + return f[i][j] + } + a := (coins[i] >> j) - k + b := coins[i] >> (j + 1) + for _, c := range g[i] { + if c != fa { + a += dfs(c, i, j) + if j < 14 { + b += dfs(c, i, j+1) + } + } + } + f[i][j] = max(a, b) + return f[i][j] + } + return dfs(0, -1, 0) +} +``` + +### **TypeScript** +```ts +function maximumPoints(edges: number[][], coins: number[], k: number): number { + const n = coins.length; + const f: number[][] = Array.from({ length: n }, () => Array(15).fill(-1)); + const g: number[][] = Array.from({ length: n }, () => []); + for (const [a, b] of edges) { + g[a].push(b); + g[b].push(a); + } + const dfs = (i: number, fa: number, j: number): number => { + if (f[i][j] !== -1) { + return f[i][j]; + } + let a = (coins[i] >> j) - k; + let b = coins[i] >> (j + 1); + for (const c of g[i]) { + if (c !== fa) { + a += dfs(c, i, j); + if (j < 14) { + b += dfs(c, i, j + 1); + } + } + } + return (f[i][j] = Math.max(a, b)); + }; + return dfs(0, -1, 0); +} ``` ### **...** diff --git a/solution/2900-2999/2920.Maximum Points After Collecting Coins From All Nodes/Solution.cpp b/solution/2900-2999/2920.Maximum Points After Collecting Coins From All Nodes/Solution.cpp new file mode 100644 index 0000000000000..e5d1388d305f2 --- /dev/null +++ b/solution/2900-2999/2920.Maximum Points After Collecting Coins From All Nodes/Solution.cpp @@ -0,0 +1,31 @@ +class Solution { +public: + int maximumPoints(vector>& edges, vector& coins, int k) { + int n = coins.size(); + int f[n][15]; + memset(f, -1, sizeof(f)); + vector g[n]; + for (auto& e : edges) { + int a = e[0], b = e[1]; + g[a].emplace_back(b); + g[b].emplace_back(a); + } + function dfs = [&](int i, int fa, int j) { + if (f[i][j] != -1) { + return f[i][j]; + } + int a = (coins[i] >> j) - k; + int b = coins[i] >> (j + 1); + for (int c : g[i]) { + if (c != fa) { + a += dfs(c, i, j); + if (j < 14) { + b += dfs(c, i, j + 1); + } + } + } + return f[i][j] = max(a, b); + }; + return dfs(0, -1, 0); + } +}; \ No newline at end of file diff --git a/solution/2900-2999/2920.Maximum Points After Collecting Coins From All Nodes/Solution.go b/solution/2900-2999/2920.Maximum Points After Collecting Coins From All Nodes/Solution.go new file mode 100644 index 0000000000000..04fa4260e607a --- /dev/null +++ b/solution/2900-2999/2920.Maximum Points After Collecting Coins From All Nodes/Solution.go @@ -0,0 +1,35 @@ +func maximumPoints(edges [][]int, coins []int, k int) int { + n := len(coins) + f := make([][]int, n) + for i := range f { + f[i] = make([]int, 15) + for j := range f[i] { + f[i][j] = -1 + } + } + g := make([][]int, n) + for _, e := range edges { + a, b := e[0], e[1] + g[a] = append(g[a], b) + g[b] = append(g[b], a) + } + var dfs func(int, int, int) int + dfs = func(i, fa, j int) int { + if f[i][j] != -1 { + return f[i][j] + } + a := (coins[i] >> j) - k + b := coins[i] >> (j + 1) + for _, c := range g[i] { + if c != fa { + a += dfs(c, i, j) + if j < 14 { + b += dfs(c, i, j+1) + } + } + } + f[i][j] = max(a, b) + return f[i][j] + } + return dfs(0, -1, 0) +} \ No newline at end of file diff --git a/solution/2900-2999/2920.Maximum Points After Collecting Coins From All Nodes/Solution.java b/solution/2900-2999/2920.Maximum Points After Collecting Coins From All Nodes/Solution.java new file mode 100644 index 0000000000000..070f0748042de --- /dev/null +++ b/solution/2900-2999/2920.Maximum Points After Collecting Coins From All Nodes/Solution.java @@ -0,0 +1,38 @@ +class Solution { + private int k; + private int[] coins; + private Integer[][] f; + private List[] g; + + public int maximumPoints(int[][] edges, int[] coins, int k) { + this.k = k; + this.coins = coins; + int n = coins.length; + f = new Integer[n][15]; + g = new List[n]; + Arrays.setAll(g, i -> new ArrayList<>()); + for (var e : edges) { + int a = e[0], b = e[1]; + g[a].add(b); + g[b].add(a); + } + return dfs(0, -1, 0); + } + + private int dfs(int i, int fa, int j) { + if (f[i][j] != null) { + return f[i][j]; + } + int a = (coins[i] >> j) - k; + int b = coins[i] >> (j + 1); + for (int c : g[i]) { + if (c != fa) { + a += dfs(c, i, j); + if (j < 14) { + b += dfs(c, i, j + 1); + } + } + } + return f[i][j] = Math.max(a, b); + } +} \ No newline at end of file diff --git a/solution/2900-2999/2920.Maximum Points After Collecting Coins From All Nodes/Solution.py b/solution/2900-2999/2920.Maximum Points After Collecting Coins From All Nodes/Solution.py new file mode 100644 index 0000000000000..f950656af687a --- /dev/null +++ b/solution/2900-2999/2920.Maximum Points After Collecting Coins From All Nodes/Solution.py @@ -0,0 +1,21 @@ +class Solution: + def maximumPoints(self, edges: List[List[int]], coins: List[int], k: int) -> int: + @cache + def dfs(i: int, fa: int, j: int) -> int: + a = (coins[i] >> j) - k + b = coins[i] >> (j + 1) + for c in g[i]: + if c != fa: + a += dfs(c, i, j) + if j < 14: + b += dfs(c, i, j + 1) + return max(a, b) + + n = len(coins) + g = [[] for _ in range(n)] + for a, b in edges: + g[a].append(b) + g[b].append(a) + ans = dfs(0, -1, 0) + dfs.cache_clear() + return ans diff --git a/solution/2900-2999/2920.Maximum Points After Collecting Coins From All Nodes/Solution.ts b/solution/2900-2999/2920.Maximum Points After Collecting Coins From All Nodes/Solution.ts new file mode 100644 index 0000000000000..94866b290d455 --- /dev/null +++ b/solution/2900-2999/2920.Maximum Points After Collecting Coins From All Nodes/Solution.ts @@ -0,0 +1,26 @@ +function maximumPoints(edges: number[][], coins: number[], k: number): number { + const n = coins.length; + const f: number[][] = Array.from({ length: n }, () => Array(15).fill(-1)); + const g: number[][] = Array.from({ length: n }, () => []); + for (const [a, b] of edges) { + g[a].push(b); + g[b].push(a); + } + const dfs = (i: number, fa: number, j: number): number => { + if (f[i][j] !== -1) { + return f[i][j]; + } + let a = (coins[i] >> j) - k; + let b = coins[i] >> (j + 1); + for (const c of g[i]) { + if (c !== fa) { + a += dfs(c, i, j); + if (j < 14) { + b += dfs(c, i, j + 1); + } + } + } + return (f[i][j] = Math.max(a, b)); + }; + return dfs(0, -1, 0); +}