From 408701e78bc167487986435f84efcb36d6650455 Mon Sep 17 00:00:00 2001 From: Libin YANG Date: Mon, 11 Dec 2023 10:57:22 +0800 Subject: [PATCH 1/5] feat: add solutions to lc problem: No.1631 (#2081) No.1631.Path With Minimum Effort --- .../1631.Path With Minimum Effort/README.md | 806 +++++++++++------- .../README_EN.md | 749 +++++++++++----- .../Solution.cpp | 29 +- .../1631.Path With Minimum Effort/Solution.go | 67 +- .../Solution.java | 23 +- .../1631.Path With Minimum Effort/Solution.py | 17 +- .../1631.Path With Minimum Effort/Solution.ts | 23 + 7 files changed, 1138 insertions(+), 576 deletions(-) create mode 100644 solution/1600-1699/1631.Path With Minimum Effort/Solution.ts diff --git a/solution/1600-1699/1631.Path With Minimum Effort/README.md b/solution/1600-1699/1631.Path With Minimum Effort/README.md index dc31ce7a69135..738627548a83b 100644 --- a/solution/1600-1699/1631.Path With Minimum Effort/README.md +++ b/solution/1600-1699/1631.Path With Minimum Effort/README.md @@ -60,82 +60,29 @@ **方法一:并查集** -对于本题,每个格子当做图的一个节点,把相邻两个格子的高度差绝对值当做边的权重,因此本题是求解从最左上角的节点到最右下角的节点的连通性问题。 +对于本题,我们可以把每个格子当做图的一个节点,把相邻两个格子的高度差绝对值当做边的权重,因此本题是求解从最左上角的节点到最右下角的节点的连通性问题。 -先把图中所有边去掉,然后按照边的权重从小到大,逐个把边添加上。如果在某一次添加一条边时,最左上角和最右下角的节点连通了,那么该边的权重就是题目的最小体力消耗值。 +我们先构建一个边集,然后按照边的权重从小到大进行排序,逐个添加边,直到最左上角的节点和最右下角的节点连通为止,此时的边的权重就是题目的最小体力消耗值。 -并查集模板: +时间复杂度 $O(m \times n \times \log(m \times n))$,空间复杂度 $O(m \times n)$。其中 $m$ 和 $n$ 分别是二维数组的行数和列数。 -模板 1——朴素并查集: - -```python -# 初始化,p存储每个点的父节点 -p = list(range(n)) - - -# 返回x的祖宗节点 -def find(x): - if p[x] != x: - # 路径压缩 - p[x] = find(p[x]) - return p[x] - - -# 合并a和b所在的两个集合 -p[find(a)] = find(b) -``` - -模板 2——维护 size 的并查集: - -```python -# 初始化,p存储每个点的父节点,size只有当节点是祖宗节点时才有意义,表示祖宗节点所在集合中,点的数量 -p = list(range(n)) -size = [1] * n - - -# 返回x的祖宗节点 -def find(x): - if p[x] != x: - # 路径压缩 - p[x] = find(p[x]) - return p[x] - - -# 合并a和b所在的两个集合 -if find(a) != find(b): - size[find(b)] += size[find(a)] - p[find(a)] = find(b) -``` +**方法二:二分查找 + BFS** -模板 3——维护到祖宗节点距离的并查集: +我们注意到,如果一个路径的最大体力消耗值为 $x$,那么对于任意 $y > x$,该路径也是满足条件的,这存在着单调性,因此我们可以使用二分查找的方法,找到最小的满足条件的体力消耗值。 -```python -# 初始化,p存储每个点的父节点,d[x]存储x到p[x]的距离 -p = list(range(n)) -d = [0] * n +我们定义二分查找的左边界 $l=0$,右边界 $r=10^6$,每次取 $mid=(l+r)/2$,然后使用 BFS 判断是否存在一条从左上角到右下角的路径,使得路径上相邻节点的高度差绝对值都不大于 $mid$,如果存在,那么说明 $mid$ 还有可能是最小的满足条件的体力消耗值,因此令 $r=mid$,否则令 $l=mid+1$。 +时间复杂度 $O(m \times n \times \log M)$,空间复杂度 $O(m \times n)$。其中 $m$ 和 $n$ 分别是二维数组的行数和列数,而 $M$ 是二维数组中的最大值,本题中 $M=10^6$。 -# 返回x的祖宗节点 -def find(x): - if p[x] != x: - t = find(p[x]) - d[x] += d[p[x]] - p[x] = t - return p[x] +**方法三:堆优化的 Dijkstra 算法** +我们可以把每个格子当做图的一个节点,把相邻两个格子的高度差绝对值当做边的权重,因此本题是求解从最左上角的节点到最右下角的节点的最短路径问题。 -# 合并a和b所在的两个集合 -p[find(a)] = find(b) -d[find(a)] = distance -``` - -**方法二:二分查找 + BFS** +我们可以使用 Dijkstra 算法求解最短路径,使用优先队列(堆)来优化时间复杂度。具体地,我们维护一个大小为 $m \times n$ 的二维数组 $dist$,其中 $dist[i][j]$ 表示从左上角到节点 $(i,j)$ 的最短路径的最大权重,初始时 $dist[0][0]=0$,其余元素均为正无穷大。 -二分枚举体力消耗值,用 BFS 找到满足条件的最小消耗值即可。 +我们用优先队列(堆)来存储节点,每次从优先队列(堆)中取出权重最小的节点,然后更新其相邻节点的权重,如果相邻节点的权重发生了改变,那么就把该节点加入优先队列(堆)中。当优先队列(堆)为空时,说明我们已经找到了最短路径。 -**方法三:堆优化版 Dijkstra 算法** - -时间复杂度 O(mlogn)。 +时间复杂度 $O(m \times n \times \log(m \times n))$,空间复杂度 $O(m \times n)$。其中 $m$ 和 $n$ 分别是二维数组的行数和列数。 @@ -143,214 +90,242 @@ d[find(a)] = distance -并查集: - ```python +class UnionFind: + def __init__(self, n): + self.p = list(range(n)) + self.size = [1] * n + + def find(self, x): + if self.p[x] != x: + self.p[x] = self.find(self.p[x]) + return self.p[x] + + def union(self, a, b): + pa, pb = self.find(a), self.find(b) + if pa == pb: + return False + if self.size[pa] > self.size[pb]: + self.p[pb] = pa + self.size[pa] += self.size[pb] + else: + self.p[pa] = pb + self.size[pb] += self.size[pa] + return True + + def connected(self, a, b): + return self.find(a) == self.find(b) + + class Solution: def minimumEffortPath(self, heights: List[List[int]]) -> int: - def find(x): - if p[x] != x: - p[x] = find(p[x]) - return p[x] - m, n = len(heights), len(heights[0]) - p = list(range(m * n)) + uf = UnionFind(m * n) e = [] + dirs = (0, 1, 0) for i in range(m): for j in range(n): - if i < m - 1: - e.append( - ( - abs(heights[i][j] - heights[i + 1][j]), - i * n + j, - (i + 1) * n + j, - ) - ) - if j < n - 1: - e.append( - ( - abs(heights[i][j] - heights[i][j + 1]), - i * n + j, - i * n + j + 1, + for a, b in pairwise(dirs): + x, y = i + a, j + b + if 0 <= x < m and 0 <= y < n: + e.append( + (abs(heights[i][j] - heights[x][y]), i * n + j, x * n + y) ) - ) e.sort() - for h, i, j in e: - p[find(i)] = find(j) - if find(0) == find(m * n - 1): + for h, a, b in e: + uf.union(a, b) + if uf.connected(0, m * n - 1): return h return 0 ``` -二分查找 + BFS: - ```python class Solution: def minimumEffortPath(self, heights: List[List[int]]) -> int: - m, n = len(heights), len(heights[0]) - left, right = 0, 999999 - while left < right: - mid = (left + right) >> 1 + def check(h: int) -> bool: q = deque([(0, 0)]) vis = {(0, 0)} + dirs = (-1, 0, 1, 0, -1) while q: - i, j = q.popleft() - for a, b in [[0, 1], [0, -1], [1, 0], [-1, 0]]: - x, y = i + a, j + b - if ( - 0 <= x < m - and 0 <= y < n - and (x, y) not in vis - and abs(heights[i][j] - heights[x][y]) <= mid - ): - q.append((x, y)) - vis.add((x, y)) - if (m - 1, n - 1) in vis: - right = mid - else: - left = mid + 1 - return left -``` + for _ in range(len(q)): + i, j = q.popleft() + if i == m - 1 and j == n - 1: + return True + for a, b in pairwise(dirs): + x, y = i + a, j + b + if ( + 0 <= x < m + and 0 <= y < n + and (x, y) not in vis + and abs(heights[i][j] - heights[x][y]) <= h + ): + q.append((x, y)) + vis.add((x, y)) + return False -Dijkstra 算法: + m, n = len(heights), len(heights[0]) + return bisect_left(range(10**6), True, key=check) +``` ```python class Solution: def minimumEffortPath(self, heights: List[List[int]]) -> int: - INF = 0x3F3F3F3F m, n = len(heights), len(heights[0]) - dist = [[INF] * n for _ in range(m)] + dist = [[inf] * n for _ in range(m)] dist[0][0] = 0 - dirs = [-1, 0, 1, 0, -1] + dirs = (-1, 0, 1, 0, -1) q = [(0, 0, 0)] while q: t, i, j = heappop(q) - for k in range(4): - x, y = i + dirs[k], j + dirs[k + 1] + for a, b in pairwise(dirs): + x, y = i + a, j + b if ( 0 <= x < m and 0 <= y < n - and max(t, abs(heights[x][y] - heights[i][j])) < dist[x][y] + and (d := max(t, abs(heights[i][j] - heights[x][y]))) < dist[x][y] ): - dist[x][y] = max(t, abs(heights[x][y] - heights[i][j])) - heappush(q, (dist[x][y], x, y)) - return dist[-1][-1] + dist[x][y] = d + heappush(q, (d, x, y)) + return int(dist[-1][-1]) ``` ### **Java** -并查集: - ```java -class Solution { - private int[] p; - - public int minimumEffortPath(int[][] heights) { - int m = heights.length; - int n = heights[0].length; - p = new int[m * n]; - for (int i = 0; i < p.length; ++i) { +class UnionFind { + private final int[] p; + private final int[] size; + + public UnionFind(int n) { + p = new int[n]; + size = new int[n]; + for (int i = 0; i < n; ++i) { p[i] = i; + size[i] = 1; + } + } + + public int find(int x) { + if (p[x] != x) { + p[x] = find(p[x]); + } + return p[x]; + } + + public boolean union(int a, int b) { + int pa = find(a), pb = find(b); + if (pa == pb) { + return false; } + if (size[pa] > size[pb]) { + p[pb] = pa; + size[pa] += size[pb]; + } else { + p[pa] = pb; + size[pb] += size[pa]; + } + return true; + } + + public boolean connected(int a, int b) { + return find(a) == find(b); + } +} + +class Solution { + public int minimumEffortPath(int[][] heights) { + int m = heights.length, n = heights[0].length; + UnionFind uf = new UnionFind(m * n); List edges = new ArrayList<>(); + int[] dirs = {1, 0, 1}; for (int i = 0; i < m; ++i) { for (int j = 0; j < n; ++j) { - if (i < m - 1) { - edges.add(new int[] { - Math.abs(heights[i][j] - heights[i + 1][j]), i * n + j, (i + 1) * n + j}); - } - if (j < n - 1) { - edges.add(new int[] { - Math.abs(heights[i][j] - heights[i][j + 1]), i * n + j, i * n + j + 1}); + for (int k = 0; k < 2; ++k) { + int x = i + dirs[k], y = j + dirs[k + 1]; + if (x >= 0 && x < m && y >= 0 && y < n) { + int d = Math.abs(heights[i][j] - heights[x][y]); + edges.add(new int[] {d, i * n + j, x * n + y}); + } } } } - Collections.sort(edges, Comparator.comparingInt(a -> a[0])); + Collections.sort(edges, (a, b) -> a[0] - b[0]); for (int[] e : edges) { - int i = e[1], j = e[2]; - p[find(i)] = find(j); - if (find(0) == find(m * n - 1)) { + uf.union(e[1], e[2]); + if (uf.connected(0, m * n - 1)) { return e[0]; } } return 0; } - - private int find(int x) { - if (p[x] != x) { - p[x] = find(p[x]); - } - return p[x]; - } } ``` -二分查找 + BFS: - ```java class Solution { public int minimumEffortPath(int[][] heights) { - int m = heights.length; - int n = heights[0].length; - int left = 0; - int right = 999999; + int l = 0, r = 1000000; + while (l < r) { + int mid = (l + r) >> 1; + if (check(heights, mid)) { + r = mid; + } else { + l = mid + 1; + } + } + return l; + } + + private boolean check(int[][] heights, int h) { + int m = heights.length, n = heights[0].length; + boolean[][] vis = new boolean[m][n]; + Deque q = new ArrayDeque<>(); + q.add(new int[] {0, 0}); + vis[0][0] = true; int[] dirs = {-1, 0, 1, 0, -1}; - while (left < right) { - int mid = (left + right) >> 1; - boolean[][] vis = new boolean[m][n]; - vis[0][0] = true; - Deque q = new ArrayDeque<>(); - q.offer(new int[] {0, 0}); - while (!q.isEmpty()) { - int[] p = q.poll(); - int i = p[0], j = p[1]; - for (int k = 0; k < 4; ++k) { - int x = i + dirs[k], y = j + dirs[k + 1]; - if (x >= 0 && x < m && y >= 0 && y < n && !vis[x][y] - && Math.abs(heights[i][j] - heights[x][y]) <= mid) { - q.offer(new int[] {x, y}); - vis[x][y] = true; - } - } + while (!q.isEmpty()) { + var p = q.poll(); + int i = p[0], j = p[1]; + if (i == m - 1 && j == n - 1) { + return true; } - if (vis[m - 1][n - 1]) { - right = mid; - } else { - left = mid + 1; + for (int k = 0; k < 4; ++k) { + int x = i + dirs[k], y = j + dirs[k + 1]; + if (x >= 0 && x < m && y >= 0 && y < n && !vis[x][y] && Math.abs(heights[x][y] - heights[i][j]) <= h) { + q.add(new int[] {x, y}); + vis[x][y] = true; + } } } - return left; + return false; } } ``` -Dijkstra 算法: - ```java class Solution { public int minimumEffortPath(int[][] heights) { - int m = heights.length; - int n = heights[0].length; + int m = heights.length, n = heights[0].length; int[][] dist = new int[m][n]; - for (int i = 0; i < m; ++i) { - Arrays.fill(dist[i], 0x3f3f3f3f); + for (var row : dist) { + Arrays.fill(row, 1 << 30); } dist[0][0] = 0; - PriorityQueue q = new PriorityQueue<>(Comparator.comparingInt(a -> a[0])); - q.offer(new int[] {0, 0, 0}); int[] dirs = {-1, 0, 1, 0, -1}; - while (!q.isEmpty()) { - int[] p = q.poll(); + PriorityQueue pq = new PriorityQueue<>((a, b) -> a[0] - b[0]); + pq.offer(new int[] {0, 0, 0}); + while (!pq.isEmpty()) { + var p = pq.poll(); int t = p[0], i = p[1], j = p[2]; for (int k = 0; k < 4; ++k) { int x = i + dirs[k], y = j + dirs[k + 1]; if (x >= 0 && x < m && y >= 0 && y < n) { - int nd = Math.max(t, Math.abs(heights[x][y] - heights[i][j])); - if (nd < dist[x][y]) { - dist[x][y] = nd; - q.offer(new int[] {nd, x, y}); + int d = Math.max(t, Math.abs(heights[x][y] - heights[i][j])); + if (d < dist[x][y]) { + dist[x][y] = d; + pq.offer(new int[] {d, x, y}); } } } @@ -362,99 +337,139 @@ class Solution { ### **C++** -并查集: - ```cpp -class Solution { +class UnionFind { public: - vector p; + UnionFind(int n) { + p = vector(n); + size = vector(n, 1); + iota(p.begin(), p.end(), 0); + } + + bool unite(int a, int b) { + int pa = find(a), pb = find(b); + if (pa == pb) { + return false; + } + if (size[pa] > size[pb]) { + p[pb] = pa; + size[pa] += size[pb]; + } else { + p[pa] = pb; + size[pb] += size[pa]; + } + return true; + } + + int find(int x) { + if (p[x] != x) { + p[x] = find(p[x]); + } + return p[x]; + } + bool connected(int a, int b) { + return find(a) == find(b); + } + +private: + vector p, size; +}; + +class Solution { +public: int minimumEffortPath(vector>& heights) { int m = heights.size(), n = heights[0].size(); - p.resize(m * n); - for (int i = 0; i < p.size(); ++i) p[i] = i; - vector> edges; + vector> edges; + int dirs[3] = {0, 1, 0}; for (int i = 0; i < m; ++i) { for (int j = 0; j < n; ++j) { - if (i < m - 1) edges.push_back({abs(heights[i][j] - heights[i + 1][j]), i * n + j, (i + 1) * n + j}); - if (j < n - 1) edges.push_back({abs(heights[i][j] - heights[i][j + 1]), i * n + j, i * n + j + 1}); + for (int k = 0; k < 2; ++k) { + int x = i + dirs[k], y = j + dirs[k + 1]; + if (x >= 0 && x < m && y >= 0 && y < n) { + edges.push_back({abs(heights[i][j] - heights[x][y]), i * n + j, x * n + y}); + } + } } } sort(edges.begin(), edges.end()); - for (auto& e : edges) { - int i = e[1], j = e[2]; - p[find(i)] = find(j); - if (find(0) == find(m * n - 1)) return e[0]; + UnionFind uf(m * n); + for (auto& [h, a, b] : edges) { + uf.unite(a, b); + if (uf.connected(0, m * n - 1)) { + return h; + } } return 0; } - - int find(int x) { - if (p[x] != x) p[x] = find(p[x]); - return p[x]; - } }; ``` -二分查找 + BFS: - ```cpp class Solution { public: int minimumEffortPath(vector>& heights) { - int m = heights.size(), n = heights[0].size(); - int left = 0, right = 999999; - vector dirs = {-1, 0, 1, 0, -1}; - while (left < right) { - int mid = (left + right) >> 1; - vector> vis(m, vector(n)); + auto check = [&](int h) { + int m = heights.size(), n = heights[0].size(); + bool vis[m][n]; + memset(vis, false, sizeof(vis)); + queue> q{{{0, 0}}}; vis[0][0] = true; - queue> q; - q.push({0, 0}); + int dirs[5] = {-1, 0, 1, 0, -1}; while (!q.empty()) { auto [i, j] = q.front(); q.pop(); + if (i == m - 1 && j == n - 1) { + return true; + } for (int k = 0; k < 4; ++k) { int x = i + dirs[k], y = j + dirs[k + 1]; - if (x >= 0 && x < m && y >= 0 && y < n && !vis[x][y] && abs(heights[i][j] - heights[x][y]) <= mid) { + if (x >= 0 && x < m && y >= 0 && y < n && !vis[x][y] && abs(heights[x][y] - heights[i][j]) <= h) { q.push({x, y}); vis[x][y] = true; } } } - if (vis[m - 1][n - 1]) - right = mid; - else - left = mid + 1; + return false; + }; + int l = 0, r = 1e6; + while (l < r) { + int mid = (l + r) >> 1; + if (check(mid)) { + r = mid; + } else { + l = mid + 1; + } } - return left; + return l; } }; ``` -Dijkstra 算法: - ```cpp class Solution { public: int minimumEffortPath(vector>& heights) { int m = heights.size(), n = heights[0].size(); - vector> dist(m, vector(n, 0x3f3f3f3f)); + int dist[m][n]; + memset(dist, 0x3f, sizeof(dist)); dist[0][0] = 0; - priority_queue, vector>, greater>> q; - q.push({0, 0, 0}); - vector dirs = {-1, 0, 1, 0, -1}; - while (!q.empty()) { - auto [t, i, j] = q.top(); - q.pop(); + int dirs[5] = {0, 1, 0, -1, 0}; + using T = tuple; + priority_queue, greater> pq; + pq.emplace(0, 0, 0); + while (!pq.empty()) { + auto [t, i, j] = pq.top(); + pq.pop(); for (int k = 0; k < 4; ++k) { int x = i + dirs[k], y = j + dirs[k + 1]; - if (x >= 0 && x < m && y >= 0 && y < n) { - int nd = max(t, abs(heights[x][y] - heights[i][j])); - if (nd < dist[x][y]) { - dist[x][y] = nd; - q.push({nd, x, y}); - } + if (x < 0 || x >= m || y < 0 || y >= n) { + continue; + } + int d = max(t, abs(heights[x][y] - heights[i][j])); + if (d < dist[x][y]) { + dist[x][y] = d; + pq.emplace(d, x, y); } } } @@ -465,42 +480,66 @@ public: ### **Go** -并查集: - ```go -func minimumEffortPath(heights [][]int) int { - m, n := len(heights), len(heights[0]) - p := make([]int, m*n) +type unionFind struct { + p, size []int +} + +func newUnionFind(n int) *unionFind { + p := make([]int, n) + size := make([]int, n) for i := range p { p[i] = i + size[i] = 1 } - var find func(x int) int - find = func(x int) int { - if p[x] != x { - p[x] = find(p[x]) - } - return p[x] + return &unionFind{p, size} +} + +func (uf *unionFind) find(x int) int { + if uf.p[x] != x { + uf.p[x] = uf.find(uf.p[x]) + } + return uf.p[x] +} + +func (uf *unionFind) union(a, b int) bool { + pa, pb := uf.find(a), uf.find(b) + if pa == pb { + return false + } + if uf.size[pa] > uf.size[pb] { + uf.p[pb] = pa + uf.size[pa] += uf.size[pb] + } else { + uf.p[pa] = pb + uf.size[pb] += uf.size[pa] } - edges := [][]int{} + return true +} + +func (uf *unionFind) connected(a, b int) bool { + return uf.find(a) == uf.find(b) +} + +func minimumEffortPath(heights [][]int) int { + m, n := len(heights), len(heights[0]) + edges := make([][3]int, 0, m*n*2) + dirs := [3]int{0, 1, 0} for i, row := range heights { for j, h := range row { - if i < m-1 { - s := []int{abs(h - heights[i+1][j]), i*n + j, (i+1)*n + j} - edges = append(edges, s) - } - if j < n-1 { - s := []int{abs(h - row[j+1]), i*n + j, i*n + j + 1} - edges = append(edges, s) + for k := 0; k < 2; k++ { + x, y := i+dirs[k], j+dirs[k+1] + if x >= 0 && x < m && y >= 0 && y < n { + edges = append(edges, [3]int{abs(h - heights[x][y]), i*n + j, x*n + y}) + } } } } - sort.Slice(edges, func(i, j int) bool { - return edges[i][0] < edges[j][0] - }) + sort.Slice(edges, func(i, j int) bool { return edges[i][0] < edges[j][0] }) + uf := newUnionFind(m * n) for _, e := range edges { - i, j := e[1], e[2] - p[find(i)] = find(j) - if find(0) == find(m*n-1) { + uf.union(e[1], e[2]) + if uf.connected(0, m*n-1) { return e[0] } } @@ -508,54 +547,243 @@ func minimumEffortPath(heights [][]int) int { } func abs(x int) int { - if x > 0 { - return x + if x < 0 { + return -x } - return -x + return x } ``` -二分查找 + BFS: - ```go func minimumEffortPath(heights [][]int) int { - m, n := len(heights), len(heights[0]) - left, right := 0, 999999 - dirs := []int{-1, 0, 1, 0, -1} - for left < right { - mid := (left + right) >> 1 + return sort.Search(1e6, func(h int) bool { + m, n := len(heights), len(heights[0]) vis := make([][]bool, m) for i := range vis { vis[i] = make([]bool, n) } vis[0][0] = true - q := [][]int{{0, 0}} + q := [][2]int{} + q = append(q, [2]int{0, 0}) + dirs := [5]int{-1, 0, 1, 0, -1} for len(q) > 0 { p := q[0] q = q[1:] i, j := p[0], p[1] + if i == m-1 && j == n-1 { + return true + } for k := 0; k < 4; k++ { x, y := i+dirs[k], j+dirs[k+1] - if x >= 0 && x < m && y >= 0 && y < n && !vis[x][y] && abs(heights[i][j]-heights[x][y]) <= mid { - q = append(q, []int{x, y}) + if x >= 0 && x < m && y >= 0 && y < n && !vis[x][y] && abs(heights[x][y]-heights[i][j]) <= h { vis[x][y] = true + q = append(q, [2]int{x, y}) } } } - if vis[m-1][n-1] { - right = mid - } else { - left = mid + 1 + return false + }) +} + +func abs(x int) int { + if x < 0 { + return -x + } + return x +} +``` + +```go +func minimumEffortPath(heights [][]int) int { + m, n := len(heights), len(heights[0]) + dist := make([][]int, m) + for i := range dist { + dist[i] = make([]int, n) + for j := range dist[i] { + dist[i][j] = 1 << 30 } } - return left + dirs := [5]int{-1, 0, 1, 0, -1} + dist[0][0] = 0 + pq := hp{} + heap.Push(&pq, tuple{0, 0, 0}) + for pq.Len() > 0 { + p := heap.Pop(&pq).(tuple) + t, i, j := p.t, p.i, p.j + for k := 0; k < 4; k++ { + x, y := i+dirs[k], j+dirs[k+1] + if x >= 0 && x < m && y >= 0 && y < n { + if d := max(t, abs(heights[x][y]-heights[i][j])); d < dist[x][y] { + dist[x][y] = d + heap.Push(&pq, tuple{d, x, y}) + } + } + } + } + return dist[m-1][n-1] } func abs(x int) int { - if x > 0 { - return x + if x < 0 { + return -x } - return -x + return x +} + +type tuple struct{ t, i, j int } +type hp []tuple + +func (h hp) Len() int { return len(h) } +func (h hp) Less(i, j int) bool { return h[i].t < h[j].t } +func (h hp) Swap(i, j int) { h[i], h[j] = h[j], h[i] } +func (h *hp) Push(v any) { *h = append(*h, v.(tuple)) } +func (h *hp) Pop() any { a := *h; v := a[len(a)-1]; *h = a[:len(a)-1]; return v } +``` + +### **TypeScript** + +```ts +class UnionFind { + private p: number[]; + private size: number[]; + + constructor(n: number) { + this.p = Array.from({ length: n }, (_, i) => i); + this.size = Array(n).fill(1); + } + + find(x: number): number { + if (this.p[x] !== x) { + this.p[x] = this.find(this.p[x]); + } + return this.p[x]; + } + + union(a: number, b: number): boolean { + const pa = this.find(a); + const pb = this.find(b); + if (pa === pb) { + return false; + } + if (this.size[pa] > this.size[pb]) { + this.p[pb] = pa; + this.size[pa] += this.size[pb]; + } else { + this.p[pa] = pb; + this.size[pb] += this.size[pa]; + } + return true; + } + + connected(a: number, b: number): boolean { + return this.find(a) === this.find(b); + } +} + +function minimumEffortPath(heights: number[][]): number { + const m = heights.length; + const n = heights[0].length; + const uf = new UnionFind(m * n); + const edges: number[][] = []; + const dirs = [1, 0, 1]; + + for (let i = 0; i < m; ++i) { + for (let j = 0; j < n; ++j) { + for (let k = 0; k < 2; ++k) { + const x = i + dirs[k]; + const y = j + dirs[k + 1]; + if (x >= 0 && x < m && y >= 0 && y < n) { + const d = Math.abs(heights[i][j] - heights[x][y]); + edges.push([d, i * n + j, x * n + y]); + } + } + } + } + + edges.sort((a, b) => a[0] - b[0]); + + for (const [h, a, b] of edges) { + uf.union(a, b); + if (uf.connected(0, m * n - 1)) { + return h; + } + } + + return 0; +} +``` + +```ts +function minimumEffortPath(heights: number[][]): number { + const check = (h: number): boolean => { + const m = heights.length; + const n = heights[0].length; + const vis: boolean[][] = Array.from({ length: m }, () => Array(n).fill(false)); + const dirs: number[] = [-1, 0, 1, 0, -1]; + const q: [number, number][] = [[0, 0]]; + vis[0][0] = true; + + while (q.length > 0) { + const [i, j] = q.pop()!; + if (i === m - 1 && j === n - 1) { + return true; + } + + for (let k = 0; k < 4; ++k) { + const x = i + dirs[k]; + const y = j + dirs[k + 1]; + if ( + x >= 0 && + x < m && + y >= 0 && + y < n && + !vis[x][y] && + Math.abs(heights[x][y] - heights[i][j]) <= h + ) { + q.push([x, y]); + vis[x][y] = true; + } + } + } + return false; + }; + + let [l, r] = [0, 10 ** 6]; + while (l < r) { + const mid = (l + r) >> 1; + if (check(mid)) { + r = mid; + } else { + l = mid + 1; + } + } + return l; +} +``` + +```ts +function minimumEffortPath(heights: number[][]): number { + const m = heights.length; + const n = heights[0].length; + const pq = new PriorityQueue({ compare: (a, b) => a[0] - b[0] }); + pq.enqueue([0, 0, 0]); + const dist = Array.from({ length: m }, () => Array.from({ length: n }, () => Infinity)); + dist[0][0] = 0; + const dirs = [-1, 0, 1, 0, -1]; + while (pq.size() > 0) { + const [t, i, j] = pq.dequeue()!; + for (let k = 0; k < 4; ++k) { + const [x, y] = [i + dirs[k], j + dirs[k + 1]]; + if (x >= 0 && x < m && y >= 0 && y < n) { + const d = Math.max(t, Math.abs(heights[x][y] - heights[i][j])); + if (d < dist[x][y]) { + dist[x][y] = d; + pq.enqueue([d, x, y]); + } + } + } + } + return dist[m - 1][n - 1]; } ``` diff --git a/solution/1600-1699/1631.Path With Minimum Effort/README_EN.md b/solution/1600-1699/1631.Path With Minimum Effort/README_EN.md index 4b5e16cd83376..7ce077338d4c9 100644 --- a/solution/1600-1699/1631.Path With Minimum Effort/README_EN.md +++ b/solution/1600-1699/1631.Path With Minimum Effort/README_EN.md @@ -52,187 +52,244 @@ This is better than the route of [1,2,2,2,5], where the maximum absolute differe ## Solutions -`Union find` or `Binary search + BFS`. +**Solution 1: Union-Find** + +For this problem, we can treat each cell as a node in a graph, and the absolute difference in height between two adjacent cells as the weight of the edge. Therefore, this problem is to solve the connectivity problem from the top-left node to the bottom-right node. + +We first construct a set of edges, then sort them in ascending order of edge weight, and add edges one by one until the top-left node and the bottom-right node are connected. At this point, the weight of the edge is the minimum physical consumption value required by the problem. + +The time complexity is $O(m \times n \times \log(m \times n))$, and the space complexity is $O(m \times n)$. Here, $m$ and $n$ are the number of rows and columns in the two-dimensional array, respectively. + +**Solution 2: Binary Search + BFS** + +We notice that if the maximum physical consumption value of a path is $x$, then for any $y > x$, this path also meets the conditions. This shows monotonicity, so we can use the binary search method to find the minimum physical consumption value that meets the conditions. + +We define the left boundary of the binary search as $l=0$, and the right boundary as $r=10^6$. Each time we take $mid=(l+r)/2$, then use BFS to determine whether there is a path from the top-left corner to the bottom-right corner, so that the absolute difference in height between adjacent nodes on the path is not greater than $mid$. If it exists, it means that $mid$ may still be the minimum physical consumption value that meets the conditions, so we set $r=mid$, otherwise we set $l=mid+1$. + +The time complexity is $O(m \times n \times \log M)$, and the space complexity is $O(m \times n)$. Here, $m$ and $n$ are the number of rows and columns in the two-dimensional array, respectively, and $M$ is the maximum value in the two-dimensional array. In this problem, $M=10^6$. + +**Solution 3: Heap-optimized Dijkstra Algorithm** + +We can treat each cell as a node in a graph, and the absolute difference in height between two adjacent cells as the weight of the edge. Therefore, this problem is to solve the shortest path problem from the top-left node to the bottom-right node. + +We can use the Dijkstra algorithm to solve the shortest path problem, and use a priority queue (heap) to optimize the time complexity. Specifically, we maintain a two-dimensional array $dist$ of size $m \times n$, where $dist[i][j]$ represents the maximum weight of the shortest path from the top-left corner to the node $(i,j)$. Initially, $dist[0][0]=0$, and all other elements are positive infinity. + +We use a priority queue (heap) to store nodes, and each time we take out the node with the smallest weight from the priority queue (heap), then update the weights of its adjacent nodes. If the weight of an adjacent node changes, then we add this node to the priority queue (heap). When the priority queue (heap) is empty, it means that we have found the shortest path. + +The time complexity is $O(m \times n \times \log(m \times n))$, and the space complexity is $O(m \times n)$. Here, $m$ and $n$ are the number of rows and columns in the two-dimensional array, respectively. ### **Python3** -Union find: - ```python +class UnionFind: + def __init__(self, n): + self.p = list(range(n)) + self.size = [1] * n + + def find(self, x): + if self.p[x] != x: + self.p[x] = self.find(self.p[x]) + return self.p[x] + + def union(self, a, b): + pa, pb = self.find(a), self.find(b) + if pa == pb: + return False + if self.size[pa] > self.size[pb]: + self.p[pb] = pa + self.size[pa] += self.size[pb] + else: + self.p[pa] = pb + self.size[pb] += self.size[pa] + return True + + def connected(self, a, b): + return self.find(a) == self.find(b) + + class Solution: def minimumEffortPath(self, heights: List[List[int]]) -> int: - def find(x): - if p[x] != x: - p[x] = find(p[x]) - return p[x] - m, n = len(heights), len(heights[0]) - p = list(range(m * n)) + uf = UnionFind(m * n) e = [] + dirs = (0, 1, 0) for i in range(m): for j in range(n): - if i < m - 1: - e.append( - ( - abs(heights[i][j] - heights[i + 1][j]), - i * n + j, - (i + 1) * n + j, - ) - ) - if j < n - 1: - e.append( - ( - abs(heights[i][j] - heights[i][j + 1]), - i * n + j, - i * n + j + 1, + for a, b in pairwise(dirs): + x, y = i + a, j + b + if 0 <= x < m and 0 <= y < n: + e.append( + (abs(heights[i][j] - heights[x][y]), i * n + j, x * n + y) ) - ) e.sort() - for h, i, j in e: - p[find(i)] = find(j) - if find(0) == find(m * n - 1): + for h, a, b in e: + uf.union(a, b) + if uf.connected(0, m * n - 1): return h return 0 ``` -Binary search + BFS: - ```python class Solution: def minimumEffortPath(self, heights: List[List[int]]) -> int: - m, n = len(heights), len(heights[0]) - left, right = 0, 999999 - while left < right: - mid = (left + right) >> 1 + def check(h: int) -> bool: q = deque([(0, 0)]) vis = {(0, 0)} + dirs = (-1, 0, 1, 0, -1) while q: - i, j = q.popleft() - for a, b in [[0, 1], [0, -1], [1, 0], [-1, 0]]: - x, y = i + a, j + b - if ( - 0 <= x < m - and 0 <= y < n - and (x, y) not in vis - and abs(heights[i][j] - heights[x][y]) <= mid - ): - q.append((x, y)) - vis.add((x, y)) - if (m - 1, n - 1) in vis: - right = mid - else: - left = mid + 1 - return left + for _ in range(len(q)): + i, j = q.popleft() + if i == m - 1 and j == n - 1: + return True + for a, b in pairwise(dirs): + x, y = i + a, j + b + if ( + 0 <= x < m + and 0 <= y < n + and (x, y) not in vis + and abs(heights[i][j] - heights[x][y]) <= h + ): + q.append((x, y)) + vis.add((x, y)) + return False + + m, n = len(heights), len(heights[0]) + return bisect_left(range(10**6), True, key=check) ``` ```python class Solution: def minimumEffortPath(self, heights: List[List[int]]) -> int: - INF = 0x3F3F3F3F m, n = len(heights), len(heights[0]) - dist = [[INF] * n for _ in range(m)] + dist = [[inf] * n for _ in range(m)] dist[0][0] = 0 - dirs = [-1, 0, 1, 0, -1] + dirs = (-1, 0, 1, 0, -1) q = [(0, 0, 0)] while q: t, i, j = heappop(q) - for k in range(4): - x, y = i + dirs[k], j + dirs[k + 1] + for a, b in pairwise(dirs): + x, y = i + a, j + b if ( 0 <= x < m and 0 <= y < n - and max(t, abs(heights[x][y] - heights[i][j])) < dist[x][y] + and (d := max(t, abs(heights[i][j] - heights[x][y]))) < dist[x][y] ): - dist[x][y] = max(t, abs(heights[x][y] - heights[i][j])) - heappush(q, (dist[x][y], x, y)) - return dist[-1][-1] + dist[x][y] = d + heappush(q, (d, x, y)) + return int(dist[-1][-1]) ``` ### **Java** -Union find: - ```java -class Solution { - private int[] p; - - public int minimumEffortPath(int[][] heights) { - int m = heights.length; - int n = heights[0].length; - p = new int[m * n]; - for (int i = 0; i < p.length; ++i) { +class UnionFind { + private final int[] p; + private final int[] size; + + public UnionFind(int n) { + p = new int[n]; + size = new int[n]; + for (int i = 0; i < n; ++i) { p[i] = i; + size[i] = 1; + } + } + + public int find(int x) { + if (p[x] != x) { + p[x] = find(p[x]); + } + return p[x]; + } + + public boolean union(int a, int b) { + int pa = find(a), pb = find(b); + if (pa == pb) { + return false; + } + if (size[pa] > size[pb]) { + p[pb] = pa; + size[pa] += size[pb]; + } else { + p[pa] = pb; + size[pb] += size[pa]; } + return true; + } + + public boolean connected(int a, int b) { + return find(a) == find(b); + } +} + +class Solution { + public int minimumEffortPath(int[][] heights) { + int m = heights.length, n = heights[0].length; + UnionFind uf = new UnionFind(m * n); List edges = new ArrayList<>(); + int[] dirs = {1, 0, 1}; for (int i = 0; i < m; ++i) { for (int j = 0; j < n; ++j) { - if (i < m - 1) { - edges.add(new int[] { - Math.abs(heights[i][j] - heights[i + 1][j]), i * n + j, (i + 1) * n + j}); - } - if (j < n - 1) { - edges.add(new int[] { - Math.abs(heights[i][j] - heights[i][j + 1]), i * n + j, i * n + j + 1}); + for (int k = 0; k < 2; ++k) { + int x = i + dirs[k], y = j + dirs[k + 1]; + if (x >= 0 && x < m && y >= 0 && y < n) { + int d = Math.abs(heights[i][j] - heights[x][y]); + edges.add(new int[] {d, i * n + j, x * n + y}); + } } } } - Collections.sort(edges, Comparator.comparingInt(a -> a[0])); + Collections.sort(edges, (a, b) -> a[0] - b[0]); for (int[] e : edges) { - int i = e[1], j = e[2]; - p[find(i)] = find(j); - if (find(0) == find(m * n - 1)) { + uf.union(e[1], e[2]); + if (uf.connected(0, m * n - 1)) { return e[0]; } } return 0; } - - private int find(int x) { - if (p[x] != x) { - p[x] = find(p[x]); - } - return p[x]; - } } ``` -Binary search + BFS: - ```java class Solution { public int minimumEffortPath(int[][] heights) { - int m = heights.length; - int n = heights[0].length; - int left = 0; - int right = 999999; + int l = 0, r = 1000000; + while (l < r) { + int mid = (l + r) >> 1; + if (check(heights, mid)) { + r = mid; + } else { + l = mid + 1; + } + } + return l; + } + + private boolean check(int[][] heights, int h) { + int m = heights.length, n = heights[0].length; + boolean[][] vis = new boolean[m][n]; + Deque q = new ArrayDeque<>(); + q.add(new int[] {0, 0}); + vis[0][0] = true; int[] dirs = {-1, 0, 1, 0, -1}; - while (left < right) { - int mid = (left + right) >> 1; - boolean[][] vis = new boolean[m][n]; - vis[0][0] = true; - Deque q = new ArrayDeque<>(); - q.offer(new int[] {0, 0}); - while (!q.isEmpty()) { - int[] p = q.poll(); - int i = p[0], j = p[1]; - for (int k = 0; k < 4; ++k) { - int x = i + dirs[k], y = j + dirs[k + 1]; - if (x >= 0 && x < m && y >= 0 && y < n && !vis[x][y] - && Math.abs(heights[i][j] - heights[x][y]) <= mid) { - q.offer(new int[] {x, y}); - vis[x][y] = true; - } - } + while (!q.isEmpty()) { + var p = q.poll(); + int i = p[0], j = p[1]; + if (i == m - 1 && j == n - 1) { + return true; } - if (vis[m - 1][n - 1]) { - right = mid; - } else { - left = mid + 1; + for (int k = 0; k < 4; ++k) { + int x = i + dirs[k], y = j + dirs[k + 1]; + if (x >= 0 && x < m && y >= 0 && y < n && !vis[x][y] && Math.abs(heights[x][y] - heights[i][j]) <= h) { + q.add(new int[] {x, y}); + vis[x][y] = true; + } } } - return left; + return false; } } ``` @@ -240,26 +297,25 @@ class Solution { ```java class Solution { public int minimumEffortPath(int[][] heights) { - int m = heights.length; - int n = heights[0].length; + int m = heights.length, n = heights[0].length; int[][] dist = new int[m][n]; - for (int i = 0; i < m; ++i) { - Arrays.fill(dist[i], 0x3f3f3f3f); + for (var row : dist) { + Arrays.fill(row, 1 << 30); } dist[0][0] = 0; - PriorityQueue q = new PriorityQueue<>(Comparator.comparingInt(a -> a[0])); - q.offer(new int[] {0, 0, 0}); int[] dirs = {-1, 0, 1, 0, -1}; - while (!q.isEmpty()) { - int[] p = q.poll(); + PriorityQueue pq = new PriorityQueue<>((a, b) -> a[0] - b[0]); + pq.offer(new int[] {0, 0, 0}); + while (!pq.isEmpty()) { + var p = pq.poll(); int t = p[0], i = p[1], j = p[2]; for (int k = 0; k < 4; ++k) { int x = i + dirs[k], y = j + dirs[k + 1]; if (x >= 0 && x < m && y >= 0 && y < n) { - int nd = Math.max(t, Math.abs(heights[x][y] - heights[i][j])); - if (nd < dist[x][y]) { - dist[x][y] = nd; - q.offer(new int[] {nd, x, y}); + int d = Math.max(t, Math.abs(heights[x][y] - heights[i][j])); + if (d < dist[x][y]) { + dist[x][y] = d; + pq.offer(new int[] {d, x, y}); } } } @@ -271,72 +327,111 @@ class Solution { ### **C++** -Union find: - ```cpp -class Solution { +class UnionFind { public: - vector p; + UnionFind(int n) { + p = vector(n); + size = vector(n, 1); + iota(p.begin(), p.end(), 0); + } + + bool unite(int a, int b) { + int pa = find(a), pb = find(b); + if (pa == pb) { + return false; + } + if (size[pa] > size[pb]) { + p[pb] = pa; + size[pa] += size[pb]; + } else { + p[pa] = pb; + size[pb] += size[pa]; + } + return true; + } + + int find(int x) { + if (p[x] != x) { + p[x] = find(p[x]); + } + return p[x]; + } + bool connected(int a, int b) { + return find(a) == find(b); + } + +private: + vector p, size; +}; + +class Solution { +public: int minimumEffortPath(vector>& heights) { int m = heights.size(), n = heights[0].size(); - p.resize(m * n); - for (int i = 0; i < p.size(); ++i) p[i] = i; - vector> edges; + vector> edges; + int dirs[3] = {0, 1, 0}; for (int i = 0; i < m; ++i) { for (int j = 0; j < n; ++j) { - if (i < m - 1) edges.push_back({abs(heights[i][j] - heights[i + 1][j]), i * n + j, (i + 1) * n + j}); - if (j < n - 1) edges.push_back({abs(heights[i][j] - heights[i][j + 1]), i * n + j, i * n + j + 1}); + for (int k = 0; k < 2; ++k) { + int x = i + dirs[k], y = j + dirs[k + 1]; + if (x >= 0 && x < m && y >= 0 && y < n) { + edges.push_back({abs(heights[i][j] - heights[x][y]), i * n + j, x * n + y}); + } + } } } sort(edges.begin(), edges.end()); - for (auto& e : edges) { - int i = e[1], j = e[2]; - p[find(i)] = find(j); - if (find(0) == find(m * n - 1)) return e[0]; + UnionFind uf(m * n); + for (auto& [h, a, b] : edges) { + uf.unite(a, b); + if (uf.connected(0, m * n - 1)) { + return h; + } } return 0; } - - int find(int x) { - if (p[x] != x) p[x] = find(p[x]); - return p[x]; - } }; ``` -Binary search + BFS: - ```cpp class Solution { public: int minimumEffortPath(vector>& heights) { - int m = heights.size(), n = heights[0].size(); - int left = 0, right = 999999; - vector dirs = {-1, 0, 1, 0, -1}; - while (left < right) { - int mid = (left + right) >> 1; - vector> vis(m, vector(n)); + auto check = [&](int h) { + int m = heights.size(), n = heights[0].size(); + bool vis[m][n]; + memset(vis, false, sizeof(vis)); + queue> q{{{0, 0}}}; vis[0][0] = true; - queue> q; - q.push({0, 0}); + int dirs[5] = {-1, 0, 1, 0, -1}; while (!q.empty()) { auto [i, j] = q.front(); q.pop(); + if (i == m - 1 && j == n - 1) { + return true; + } for (int k = 0; k < 4; ++k) { int x = i + dirs[k], y = j + dirs[k + 1]; - if (x >= 0 && x < m && y >= 0 && y < n && !vis[x][y] && abs(heights[i][j] - heights[x][y]) <= mid) { + if (x >= 0 && x < m && y >= 0 && y < n && !vis[x][y] && abs(heights[x][y] - heights[i][j]) <= h) { q.push({x, y}); vis[x][y] = true; } } } - if (vis[m - 1][n - 1]) - right = mid; - else - left = mid + 1; + return false; + }; + int l = 0, r = 1e6; + while (l < r) { + int mid = (l + r) >> 1; + if (check(mid)) { + r = mid; + } else { + l = mid + 1; + } } - return left; + return l; } }; ``` @@ -346,22 +441,25 @@ class Solution { public: int minimumEffortPath(vector>& heights) { int m = heights.size(), n = heights[0].size(); - vector> dist(m, vector(n, 0x3f3f3f3f)); + int dist[m][n]; + memset(dist, 0x3f, sizeof(dist)); dist[0][0] = 0; - priority_queue, vector>, greater>> q; - q.push({0, 0, 0}); - vector dirs = {-1, 0, 1, 0, -1}; - while (!q.empty()) { - auto [t, i, j] = q.top(); - q.pop(); + int dirs[5] = {0, 1, 0, -1, 0}; + using T = tuple; + priority_queue, greater> pq; + pq.emplace(0, 0, 0); + while (!pq.empty()) { + auto [t, i, j] = pq.top(); + pq.pop(); for (int k = 0; k < 4; ++k) { int x = i + dirs[k], y = j + dirs[k + 1]; - if (x >= 0 && x < m && y >= 0 && y < n) { - int nd = max(t, abs(heights[x][y] - heights[i][j])); - if (nd < dist[x][y]) { - dist[x][y] = nd; - q.push({nd, x, y}); - } + if (x < 0 || x >= m || y < 0 || y >= n) { + continue; + } + int d = max(t, abs(heights[x][y] - heights[i][j])); + if (d < dist[x][y]) { + dist[x][y] = d; + pq.emplace(d, x, y); } } } @@ -372,42 +470,66 @@ public: ### **Go** -Union find: - ```go -func minimumEffortPath(heights [][]int) int { - m, n := len(heights), len(heights[0]) - p := make([]int, m*n) +type unionFind struct { + p, size []int +} + +func newUnionFind(n int) *unionFind { + p := make([]int, n) + size := make([]int, n) for i := range p { p[i] = i + size[i] = 1 } - var find func(x int) int - find = func(x int) int { - if p[x] != x { - p[x] = find(p[x]) - } - return p[x] + return &unionFind{p, size} +} + +func (uf *unionFind) find(x int) int { + if uf.p[x] != x { + uf.p[x] = uf.find(uf.p[x]) + } + return uf.p[x] +} + +func (uf *unionFind) union(a, b int) bool { + pa, pb := uf.find(a), uf.find(b) + if pa == pb { + return false + } + if uf.size[pa] > uf.size[pb] { + uf.p[pb] = pa + uf.size[pa] += uf.size[pb] + } else { + uf.p[pa] = pb + uf.size[pb] += uf.size[pa] } - edges := [][]int{} + return true +} + +func (uf *unionFind) connected(a, b int) bool { + return uf.find(a) == uf.find(b) +} + +func minimumEffortPath(heights [][]int) int { + m, n := len(heights), len(heights[0]) + edges := make([][3]int, 0, m*n*2) + dirs := [3]int{0, 1, 0} for i, row := range heights { for j, h := range row { - if i < m-1 { - s := []int{abs(h - heights[i+1][j]), i*n + j, (i+1)*n + j} - edges = append(edges, s) - } - if j < n-1 { - s := []int{abs(h - row[j+1]), i*n + j, i*n + j + 1} - edges = append(edges, s) + for k := 0; k < 2; k++ { + x, y := i+dirs[k], j+dirs[k+1] + if x >= 0 && x < m && y >= 0 && y < n { + edges = append(edges, [3]int{abs(h - heights[x][y]), i*n + j, x*n + y}) + } } } } - sort.Slice(edges, func(i, j int) bool { - return edges[i][0] < edges[j][0] - }) + sort.Slice(edges, func(i, j int) bool { return edges[i][0] < edges[j][0] }) + uf := newUnionFind(m * n) for _, e := range edges { - i, j := e[1], e[2] - p[find(i)] = find(j) - if find(0) == find(m*n-1) { + uf.union(e[1], e[2]) + if uf.connected(0, m*n-1) { return e[0] } } @@ -415,54 +537,243 @@ func minimumEffortPath(heights [][]int) int { } func abs(x int) int { - if x > 0 { - return x + if x < 0 { + return -x } - return -x + return x } ``` -Binary search + BFS: - ```go func minimumEffortPath(heights [][]int) int { - m, n := len(heights), len(heights[0]) - left, right := 0, 999999 - dirs := []int{-1, 0, 1, 0, -1} - for left < right { - mid := (left + right) >> 1 + return sort.Search(1e6, func(h int) bool { + m, n := len(heights), len(heights[0]) vis := make([][]bool, m) for i := range vis { vis[i] = make([]bool, n) } vis[0][0] = true - q := [][]int{{0, 0}} + q := [][2]int{} + q = append(q, [2]int{0, 0}) + dirs := [5]int{-1, 0, 1, 0, -1} for len(q) > 0 { p := q[0] q = q[1:] i, j := p[0], p[1] + if i == m-1 && j == n-1 { + return true + } for k := 0; k < 4; k++ { x, y := i+dirs[k], j+dirs[k+1] - if x >= 0 && x < m && y >= 0 && y < n && !vis[x][y] && abs(heights[i][j]-heights[x][y]) <= mid { - q = append(q, []int{x, y}) + if x >= 0 && x < m && y >= 0 && y < n && !vis[x][y] && abs(heights[x][y]-heights[i][j]) <= h { vis[x][y] = true + q = append(q, [2]int{x, y}) } } } - if vis[m-1][n-1] { - right = mid - } else { - left = mid + 1 + return false + }) +} + +func abs(x int) int { + if x < 0 { + return -x + } + return x +} +``` + +```go +func minimumEffortPath(heights [][]int) int { + m, n := len(heights), len(heights[0]) + dist := make([][]int, m) + for i := range dist { + dist[i] = make([]int, n) + for j := range dist[i] { + dist[i][j] = 1 << 30 } } - return left + dirs := [5]int{-1, 0, 1, 0, -1} + dist[0][0] = 0 + pq := hp{} + heap.Push(&pq, tuple{0, 0, 0}) + for pq.Len() > 0 { + p := heap.Pop(&pq).(tuple) + t, i, j := p.t, p.i, p.j + for k := 0; k < 4; k++ { + x, y := i+dirs[k], j+dirs[k+1] + if x >= 0 && x < m && y >= 0 && y < n { + if d := max(t, abs(heights[x][y]-heights[i][j])); d < dist[x][y] { + dist[x][y] = d + heap.Push(&pq, tuple{d, x, y}) + } + } + } + } + return dist[m-1][n-1] } func abs(x int) int { - if x > 0 { - return x + if x < 0 { + return -x } - return -x + return x +} + +type tuple struct{ t, i, j int } +type hp []tuple + +func (h hp) Len() int { return len(h) } +func (h hp) Less(i, j int) bool { return h[i].t < h[j].t } +func (h hp) Swap(i, j int) { h[i], h[j] = h[j], h[i] } +func (h *hp) Push(v any) { *h = append(*h, v.(tuple)) } +func (h *hp) Pop() any { a := *h; v := a[len(a)-1]; *h = a[:len(a)-1]; return v } +``` + +### **TypeScript** + +```ts +class UnionFind { + private p: number[]; + private size: number[]; + + constructor(n: number) { + this.p = Array.from({ length: n }, (_, i) => i); + this.size = Array(n).fill(1); + } + + find(x: number): number { + if (this.p[x] !== x) { + this.p[x] = this.find(this.p[x]); + } + return this.p[x]; + } + + union(a: number, b: number): boolean { + const pa = this.find(a); + const pb = this.find(b); + if (pa === pb) { + return false; + } + if (this.size[pa] > this.size[pb]) { + this.p[pb] = pa; + this.size[pa] += this.size[pb]; + } else { + this.p[pa] = pb; + this.size[pb] += this.size[pa]; + } + return true; + } + + connected(a: number, b: number): boolean { + return this.find(a) === this.find(b); + } +} + +function minimumEffortPath(heights: number[][]): number { + const m = heights.length; + const n = heights[0].length; + const uf = new UnionFind(m * n); + const edges: number[][] = []; + const dirs = [1, 0, 1]; + + for (let i = 0; i < m; ++i) { + for (let j = 0; j < n; ++j) { + for (let k = 0; k < 2; ++k) { + const x = i + dirs[k]; + const y = j + dirs[k + 1]; + if (x >= 0 && x < m && y >= 0 && y < n) { + const d = Math.abs(heights[i][j] - heights[x][y]); + edges.push([d, i * n + j, x * n + y]); + } + } + } + } + + edges.sort((a, b) => a[0] - b[0]); + + for (const [h, a, b] of edges) { + uf.union(a, b); + if (uf.connected(0, m * n - 1)) { + return h; + } + } + + return 0; +} +``` + +```ts +function minimumEffortPath(heights: number[][]): number { + const check = (h: number): boolean => { + const m = heights.length; + const n = heights[0].length; + const vis: boolean[][] = Array.from({ length: m }, () => Array(n).fill(false)); + const dirs: number[] = [-1, 0, 1, 0, -1]; + const q: [number, number][] = [[0, 0]]; + vis[0][0] = true; + + while (q.length > 0) { + const [i, j] = q.pop()!; + if (i === m - 1 && j === n - 1) { + return true; + } + + for (let k = 0; k < 4; ++k) { + const x = i + dirs[k]; + const y = j + dirs[k + 1]; + if ( + x >= 0 && + x < m && + y >= 0 && + y < n && + !vis[x][y] && + Math.abs(heights[x][y] - heights[i][j]) <= h + ) { + q.push([x, y]); + vis[x][y] = true; + } + } + } + return false; + }; + + let [l, r] = [0, 10 ** 6]; + while (l < r) { + const mid = (l + r) >> 1; + if (check(mid)) { + r = mid; + } else { + l = mid + 1; + } + } + return l; +} +``` + +```ts +function minimumEffortPath(heights: number[][]): number { + const m = heights.length; + const n = heights[0].length; + const pq = new PriorityQueue({ compare: (a, b) => a[0] - b[0] }); + pq.enqueue([0, 0, 0]); + const dist = Array.from({ length: m }, () => Array.from({ length: n }, () => Infinity)); + dist[0][0] = 0; + const dirs = [-1, 0, 1, 0, -1]; + while (pq.size() > 0) { + const [t, i, j] = pq.dequeue()!; + for (let k = 0; k < 4; ++k) { + const [x, y] = [i + dirs[k], j + dirs[k + 1]]; + if (x >= 0 && x < m && y >= 0 && y < n) { + const d = Math.max(t, Math.abs(heights[x][y] - heights[i][j])); + if (d < dist[x][y]) { + dist[x][y] = d; + pq.enqueue([d, x, y]); + } + } + } + } + return dist[m - 1][n - 1]; } ``` diff --git a/solution/1600-1699/1631.Path With Minimum Effort/Solution.cpp b/solution/1600-1699/1631.Path With Minimum Effort/Solution.cpp index b7338bf17b329..acf2dfedc7e94 100644 --- a/solution/1600-1699/1631.Path With Minimum Effort/Solution.cpp +++ b/solution/1600-1699/1631.Path With Minimum Effort/Solution.cpp @@ -2,22 +2,25 @@ class Solution { public: int minimumEffortPath(vector>& heights) { int m = heights.size(), n = heights[0].size(); - vector> dist(m, vector(n, 0x3f3f3f3f)); + int dist[m][n]; + memset(dist, 0x3f, sizeof(dist)); dist[0][0] = 0; - priority_queue, vector>, greater>> q; - q.push({0, 0, 0}); - vector dirs = {-1, 0, 1, 0, -1}; - while (!q.empty()) { - auto [t, i, j] = q.top(); - q.pop(); + int dirs[5] = {0, 1, 0, -1, 0}; + using T = tuple; + priority_queue, greater> pq; + pq.emplace(0, 0, 0); + while (!pq.empty()) { + auto [t, i, j] = pq.top(); + pq.pop(); for (int k = 0; k < 4; ++k) { int x = i + dirs[k], y = j + dirs[k + 1]; - if (x >= 0 && x < m && y >= 0 && y < n) { - int nd = max(t, abs(heights[x][y] - heights[i][j])); - if (nd < dist[x][y]) { - dist[x][y] = nd; - q.push({nd, x, y}); - } + if (x < 0 || x >= m || y < 0 || y >= n) { + continue; + } + int d = max(t, abs(heights[x][y] - heights[i][j])); + if (d < dist[x][y]) { + dist[x][y] = d; + pq.emplace(d, x, y); } } } diff --git a/solution/1600-1699/1631.Path With Minimum Effort/Solution.go b/solution/1600-1699/1631.Path With Minimum Effort/Solution.go index 23b896d33545a..720c20d4cec79 100644 --- a/solution/1600-1699/1631.Path With Minimum Effort/Solution.go +++ b/solution/1600-1699/1631.Path With Minimum Effort/Solution.go @@ -1,45 +1,44 @@ func minimumEffortPath(heights [][]int) int { m, n := len(heights), len(heights[0]) - p := make([]int, m*n) - for i := range p { - p[i] = i - } - var find func(x int) int - find = func(x int) int { - if p[x] != x { - p[x] = find(p[x]) + dist := make([][]int, m) + for i := range dist { + dist[i] = make([]int, n) + for j := range dist[i] { + dist[i][j] = 1 << 30 } - return p[x] } - edges := [][]int{} - for i, row := range heights { - for j, h := range row { - if i < m-1 { - s := []int{abs(h - heights[i+1][j]), i*n + j, (i+1)*n + j} - edges = append(edges, s) - } - if j < n-1 { - s := []int{abs(h - row[j+1]), i*n + j, i*n + j + 1} - edges = append(edges, s) + dirs := [5]int{-1, 0, 1, 0, -1} + dist[0][0] = 0 + pq := hp{} + heap.Push(&pq, tuple{0, 0, 0}) + for pq.Len() > 0 { + p := heap.Pop(&pq).(tuple) + t, i, j := p.t, p.i, p.j + for k := 0; k < 4; k++ { + x, y := i+dirs[k], j+dirs[k+1] + if x >= 0 && x < m && y >= 0 && y < n { + if d := max(t, abs(heights[x][y]-heights[i][j])); d < dist[x][y] { + dist[x][y] = d + heap.Push(&pq, tuple{d, x, y}) + } } } } - sort.Slice(edges, func(i, j int) bool { - return edges[i][0] < edges[j][0] - }) - for _, e := range edges { - i, j := e[1], e[2] - p[find(i)] = find(j) - if find(0) == find(m*n-1) { - return e[0] - } - } - return 0 + return dist[m-1][n-1] } func abs(x int) int { - if x > 0 { - return x + if x < 0 { + return -x } - return -x -} \ No newline at end of file + return x +} + +type tuple struct{ t, i, j int } +type hp []tuple + +func (h hp) Len() int { return len(h) } +func (h hp) Less(i, j int) bool { return h[i].t < h[j].t } +func (h hp) Swap(i, j int) { h[i], h[j] = h[j], h[i] } +func (h *hp) Push(v any) { *h = append(*h, v.(tuple)) } +func (h *hp) Pop() any { a := *h; v := a[len(a)-1]; *h = a[:len(a)-1]; return v } \ No newline at end of file diff --git a/solution/1600-1699/1631.Path With Minimum Effort/Solution.java b/solution/1600-1699/1631.Path With Minimum Effort/Solution.java index fbd3557e95ea3..bca23f677acbd 100644 --- a/solution/1600-1699/1631.Path With Minimum Effort/Solution.java +++ b/solution/1600-1699/1631.Path With Minimum Effort/Solution.java @@ -1,25 +1,24 @@ class Solution { public int minimumEffortPath(int[][] heights) { - int m = heights.length; - int n = heights[0].length; + int m = heights.length, n = heights[0].length; int[][] dist = new int[m][n]; - for (int i = 0; i < m; ++i) { - Arrays.fill(dist[i], 0x3f3f3f3f); + for (var row : dist) { + Arrays.fill(row, 1 << 30); } dist[0][0] = 0; - PriorityQueue q = new PriorityQueue<>(Comparator.comparingInt(a -> a[0])); - q.offer(new int[] {0, 0, 0}); int[] dirs = {-1, 0, 1, 0, -1}; - while (!q.isEmpty()) { - int[] p = q.poll(); + PriorityQueue pq = new PriorityQueue<>((a, b) -> a[0] - b[0]); + pq.offer(new int[] {0, 0, 0}); + while (!pq.isEmpty()) { + var p = pq.poll(); int t = p[0], i = p[1], j = p[2]; for (int k = 0; k < 4; ++k) { int x = i + dirs[k], y = j + dirs[k + 1]; if (x >= 0 && x < m && y >= 0 && y < n) { - int nd = Math.max(t, Math.abs(heights[x][y] - heights[i][j])); - if (nd < dist[x][y]) { - dist[x][y] = nd; - q.offer(new int[] {nd, x, y}); + int d = Math.max(t, Math.abs(heights[x][y] - heights[i][j])); + if (d < dist[x][y]) { + dist[x][y] = d; + pq.offer(new int[] {d, x, y}); } } } diff --git a/solution/1600-1699/1631.Path With Minimum Effort/Solution.py b/solution/1600-1699/1631.Path With Minimum Effort/Solution.py index 517055e19c83b..d3b5b9a7c46ce 100644 --- a/solution/1600-1699/1631.Path With Minimum Effort/Solution.py +++ b/solution/1600-1699/1631.Path With Minimum Effort/Solution.py @@ -1,20 +1,19 @@ class Solution: def minimumEffortPath(self, heights: List[List[int]]) -> int: - INF = 0x3F3F3F3F m, n = len(heights), len(heights[0]) - dist = [[INF] * n for _ in range(m)] + dist = [[inf] * n for _ in range(m)] dist[0][0] = 0 - dirs = [-1, 0, 1, 0, -1] + dirs = (-1, 0, 1, 0, -1) q = [(0, 0, 0)] while q: t, i, j = heappop(q) - for k in range(4): - x, y = i + dirs[k], j + dirs[k + 1] + for a, b in pairwise(dirs): + x, y = i + a, j + b if ( 0 <= x < m and 0 <= y < n - and max(t, abs(heights[x][y] - heights[i][j])) < dist[x][y] + and (d := max(t, abs(heights[i][j] - heights[x][y]))) < dist[x][y] ): - dist[x][y] = max(t, abs(heights[x][y] - heights[i][j])) - heappush(q, (dist[x][y], x, y)) - return dist[-1][-1] + dist[x][y] = d + heappush(q, (d, x, y)) + return int(dist[-1][-1]) diff --git a/solution/1600-1699/1631.Path With Minimum Effort/Solution.ts b/solution/1600-1699/1631.Path With Minimum Effort/Solution.ts new file mode 100644 index 0000000000000..e118242bb00e3 --- /dev/null +++ b/solution/1600-1699/1631.Path With Minimum Effort/Solution.ts @@ -0,0 +1,23 @@ +function minimumEffortPath(heights: number[][]): number { + const m = heights.length; + const n = heights[0].length; + const pq = new PriorityQueue({ compare: (a, b) => a[0] - b[0] }); + pq.enqueue([0, 0, 0]); + const dist = Array.from({ length: m }, () => Array.from({ length: n }, () => Infinity)); + dist[0][0] = 0; + const dirs = [-1, 0, 1, 0, -1]; + while (pq.size() > 0) { + const [t, i, j] = pq.dequeue()!; + for (let k = 0; k < 4; ++k) { + const [x, y] = [i + dirs[k], j + dirs[k + 1]]; + if (x >= 0 && x < m && y >= 0 && y < n) { + const d = Math.max(t, Math.abs(heights[x][y] - heights[i][j])); + if (d < dist[x][y]) { + dist[x][y] = d; + pq.enqueue([d, x, y]); + } + } + } + } + return dist[m - 1][n - 1]; +} From 0b44537c54a7fb74b2cd03aee85995f2ac672159 Mon Sep 17 00:00:00 2001 From: Libin YANG Date: Mon, 11 Dec 2023 14:03:14 +0800 Subject: [PATCH 2/5] feat: add solutions to lc problem: No.2959 (#2082) No.2959.Number of Possible Sets of Closing Branches --- .../README.md | 187 +++++++++++++++++- .../README_EN.md | 187 +++++++++++++++++- .../Solution.cpp | 37 ++++ .../Solution.go | 38 ++++ .../Solution.java | 40 ++++ .../Solution.py | 25 +++ .../Solution.ts | 32 +++ 7 files changed, 540 insertions(+), 6 deletions(-) create mode 100644 solution/2900-2999/2959.Number of Possible Sets of Closing Branches/Solution.cpp create mode 100644 solution/2900-2999/2959.Number of Possible Sets of Closing Branches/Solution.go create mode 100644 solution/2900-2999/2959.Number of Possible Sets of Closing Branches/Solution.java create mode 100644 solution/2900-2999/2959.Number of Possible Sets of Closing Branches/Solution.py create mode 100644 solution/2900-2999/2959.Number of Possible Sets of Closing Branches/Solution.ts diff --git a/solution/2900-2999/2959.Number of Possible Sets of Closing Branches/README.md b/solution/2900-2999/2959.Number of Possible Sets of Closing Branches/README.md index 8c84013dd921f..9d7355b4ff7bd 100644 --- a/solution/2900-2999/2959.Number of Possible Sets of Closing Branches/README.md +++ b/solution/2900-2999/2959.Number of Possible Sets of Closing Branches/README.md @@ -86,6 +86,14 @@ +**方法一:二进制枚举 + Floyd 算法** + +我们注意到 $n \leq 10$,所以我们不妨考虑使用二进制枚举的方法来枚举所有的分部集合。 + +对于每个分部集合,我们可以使用 Floyd 算法来计算出剩余分部之间的最短距离,然后判断是否满足题目要求即可。具体地,我们先枚举中间点 $k$,再枚举起点 $i$ 和终点 $j$,如果 $g[i][k] + g[k][j] \lt g[i][j]$,那么我们就用更短的距离 $g[i][k] + g[k][j]$ 更新 $g[i][j]$。 + +时间复杂度 $O(2^n \times (n^3 + m))$,空间复杂度 $O(n^2)$。其中 $n$ 和 $m$ 分别是分部数量和道路数量。 + ### **Python3** @@ -93,7 +101,31 @@ ```python - +class Solution: + def numberOfSets(self, n: int, maxDistance: int, roads: List[List[int]]) -> int: + ans = 0 + for mask in range(1 << n): + g = [[inf] * n for _ in range(n)] + for u, v, w in roads: + if mask >> u & 1 and mask > v & 1: + g[u][v] = min(g[u][v], w) + g[v][u] = min(g[v][u], w) + for k in range(n): + if mask >> k & 1: + g[k][k] = 0 + for i in range(n): + for j in range(n): + # g[i][j] = min(g[i][j], g[i][k] + g[k][j]) + if g[i][k] + g[k][j] < g[i][j]: + g[i][j] = g[i][k] + g[k][j] + if all( + g[i][j] <= maxDistance + for i in range(n) + for j in range(n) + if mask >> i & 1 and mask >> j & 1 + ): + ans += 1 + return ans ``` ### **Java** @@ -101,19 +133,168 @@ ```java - +class Solution { + public int numberOfSets(int n, int maxDistance, int[][] roads) { + int ans = 0; + for (int mask = 0; mask < 1 << n; ++mask) { + int[][] g = new int[n][n]; + for (var e : g) { + Arrays.fill(e, 1 << 29); + } + for (var e : roads) { + int u = e[0], v = e[1], w = e[2]; + if ((mask >> u & 1) == 1 && (mask >> v & 1) == 1) { + g[u][v] = Math.min(g[u][v], w); + g[v][u] = Math.min(g[v][u], w); + } + } + for (int k = 0; k < n; ++k) { + if ((mask >> k & 1) == 1) { + g[k][k] = 0; + for (int i = 0; i < n; ++i) { + for (int j = 0; j < n; ++j) { + g[i][j] = Math.min(g[i][j], g[i][k] + g[k][j]); + } + } + } + } + int ok = 1; + for (int i = 0; i < n && ok == 1; ++i) { + for (int j = 0; j < n && ok == 1; ++j) { + if ((mask >> i & 1) == 1 && (mask >> j & 1) == 1) { + if (g[i][j] > maxDistance) { + ok = 0; + } + } + } + } + ans += ok; + } + return ans; + } +} ``` ### **C++** ```cpp - +class Solution { +public: + int numberOfSets(int n, int maxDistance, vector>& roads) { + int ans = 0; + for (int mask = 0; mask < 1 << n; ++mask) { + int g[n][n]; + memset(g, 0x3f, sizeof(g)); + for (auto& e : roads) { + int u = e[0], v = e[1], w = e[2]; + if ((mask >> u & 1) & (mask >> v & 1)) { + g[u][v] = min(g[u][v], w); + g[v][u] = min(g[v][u], w); + } + } + for (int k = 0; k < n; ++k) { + if (mask >> k & 1) { + g[k][k] = 0; + for (int i = 0; i < n; ++i) { + for (int j = 0; j < n; ++j) { + g[i][j] = min(g[i][j], g[i][k] + g[k][j]); + } + } + } + } + int ok = 1; + for (int i = 0; i < n && ok == 1; ++i) { + for (int j = 0; j < n && ok == 1; ++j) { + if ((mask >> i & 1) & (mask >> j & 1) && g[i][j] > maxDistance) { + ok = 0; + } + } + } + ans += ok; + } + return ans; + } +}; ``` ### **Go** ```go +func numberOfSets(n int, maxDistance int, roads [][]int) (ans int) { + for mask := 0; mask < 1<>u&1 == 1 && mask>>v&1 == 1 { + g[u][v] = min(g[u][v], w) + g[v][u] = min(g[v][u], w) + } + } + for k := 0; k < n; k++ { + if mask>>k&1 == 1 { + g[k][k] = 0 + for i := 0; i < n; i++ { + for j := 0; j < n; j++ { + g[i][j] = min(g[i][j], g[i][k]+g[k][j]) + } + } + } + } + ok := 1 + for i := 0; i < n && ok == 1; i++ { + for j := 0; j < n && ok == 1; j++ { + if mask>>i&1 == 1 && mask>>j&1 == 1 && g[i][j] > maxDistance { + ok = 0 + } + } + } + ans += ok + } + return +} +``` +### **TypeScript** + +```ts +function numberOfSets(n: number, maxDistance: number, roads: number[][]): number { + let ans = 0; + for (let mask = 0; mask < 1 << n; ++mask) { + const g: number[][] = Array.from({ length: n }, () => Array(n).fill(Infinity)); + for (const [u, v, w] of roads) { + if ((mask >> u) & 1 && (mask >> v) & 1) { + g[u][v] = Math.min(g[u][v], w); + g[v][u] = Math.min(g[v][u], w); + } + } + for (let k = 0; k < n; ++k) { + if ((mask >> k) & 1) { + g[k][k] = 0; + for (let i = 0; i < n; ++i) { + for (let j = 0; j < n; ++j) { + g[i][j] = Math.min(g[i][j], g[i][k] + g[k][j]); + } + } + } + } + let ok = 1; + for (let i = 0; i < n && ok; ++i) { + for (let j = 0; j < n && ok; ++j) { + if ((mask >> i) & 1 && (mask >> j) & 1 && g[i][j] > maxDistance) { + ok = 0; + } + } + } + ans += ok; + } + return ans; +} ``` ### **...** diff --git a/solution/2900-2999/2959.Number of Possible Sets of Closing Branches/README_EN.md b/solution/2900-2999/2959.Number of Possible Sets of Closing Branches/README_EN.md index b40dd7f6021d5..8c90d46158c35 100644 --- a/solution/2900-2999/2959.Number of Possible Sets of Closing Branches/README_EN.md +++ b/solution/2900-2999/2959.Number of Possible Sets of Closing Branches/README_EN.md @@ -76,30 +76,211 @@ It can be proven, that there are only 2 possible sets of closing branches. ## Solutions +**Solution 1: Binary Enumeration + Floyd Algorithm** + +We notice that $n \leq 10$, so we might as well consider using the method of binary enumeration to enumerate all subsets of departments. + +For each subset of departments, we can use the Floyd algorithm to calculate the shortest distance between the remaining departments, and then judge whether it meets the requirements of the problem. Specifically, we first enumerate the middle point $k$, then enumerate the starting point $i$ and the ending point $j$. If $g[i][k] + g[k][j] < g[i][j]$, then we update $g[i][j]$ with the shorter distance $g[i][k] + g[k][j]$. + +The time complexity is $O(2^n \times (n^3 + m))$, and the space complexity is $O(n^2)$. Here, $n$ and $m$ are the number of departments and the number of roads, respectively. + ### **Python3** ```python - +class Solution: + def numberOfSets(self, n: int, maxDistance: int, roads: List[List[int]]) -> int: + ans = 0 + for mask in range(1 << n): + g = [[inf] * n for _ in range(n)] + for u, v, w in roads: + if mask >> u & 1 and mask > v & 1: + g[u][v] = min(g[u][v], w) + g[v][u] = min(g[v][u], w) + for k in range(n): + if mask >> k & 1: + g[k][k] = 0 + for i in range(n): + for j in range(n): + # g[i][j] = min(g[i][j], g[i][k] + g[k][j]) + if g[i][k] + g[k][j] < g[i][j]: + g[i][j] = g[i][k] + g[k][j] + if all( + g[i][j] <= maxDistance + for i in range(n) + for j in range(n) + if mask >> i & 1 and mask >> j & 1 + ): + ans += 1 + return ans ``` ### **Java** ```java - +class Solution { + public int numberOfSets(int n, int maxDistance, int[][] roads) { + int ans = 0; + for (int mask = 0; mask < 1 << n; ++mask) { + int[][] g = new int[n][n]; + for (var e : g) { + Arrays.fill(e, 1 << 29); + } + for (var e : roads) { + int u = e[0], v = e[1], w = e[2]; + if ((mask >> u & 1) == 1 && (mask >> v & 1) == 1) { + g[u][v] = Math.min(g[u][v], w); + g[v][u] = Math.min(g[v][u], w); + } + } + for (int k = 0; k < n; ++k) { + if ((mask >> k & 1) == 1) { + g[k][k] = 0; + for (int i = 0; i < n; ++i) { + for (int j = 0; j < n; ++j) { + g[i][j] = Math.min(g[i][j], g[i][k] + g[k][j]); + } + } + } + } + int ok = 1; + for (int i = 0; i < n && ok == 1; ++i) { + for (int j = 0; j < n && ok == 1; ++j) { + if ((mask >> i & 1) == 1 && (mask >> j & 1) == 1) { + if (g[i][j] > maxDistance) { + ok = 0; + } + } + } + } + ans += ok; + } + return ans; + } +} ``` ### **C++** ```cpp - +class Solution { +public: + int numberOfSets(int n, int maxDistance, vector>& roads) { + int ans = 0; + for (int mask = 0; mask < 1 << n; ++mask) { + int g[n][n]; + memset(g, 0x3f, sizeof(g)); + for (auto& e : roads) { + int u = e[0], v = e[1], w = e[2]; + if ((mask >> u & 1) & (mask >> v & 1)) { + g[u][v] = min(g[u][v], w); + g[v][u] = min(g[v][u], w); + } + } + for (int k = 0; k < n; ++k) { + if (mask >> k & 1) { + g[k][k] = 0; + for (int i = 0; i < n; ++i) { + for (int j = 0; j < n; ++j) { + g[i][j] = min(g[i][j], g[i][k] + g[k][j]); + } + } + } + } + int ok = 1; + for (int i = 0; i < n && ok == 1; ++i) { + for (int j = 0; j < n && ok == 1; ++j) { + if ((mask >> i & 1) & (mask >> j & 1) && g[i][j] > maxDistance) { + ok = 0; + } + } + } + ans += ok; + } + return ans; + } +}; ``` ### **Go** ```go +func numberOfSets(n int, maxDistance int, roads [][]int) (ans int) { + for mask := 0; mask < 1<>u&1 == 1 && mask>>v&1 == 1 { + g[u][v] = min(g[u][v], w) + g[v][u] = min(g[v][u], w) + } + } + for k := 0; k < n; k++ { + if mask>>k&1 == 1 { + g[k][k] = 0 + for i := 0; i < n; i++ { + for j := 0; j < n; j++ { + g[i][j] = min(g[i][j], g[i][k]+g[k][j]) + } + } + } + } + ok := 1 + for i := 0; i < n && ok == 1; i++ { + for j := 0; j < n && ok == 1; j++ { + if mask>>i&1 == 1 && mask>>j&1 == 1 && g[i][j] > maxDistance { + ok = 0 + } + } + } + ans += ok + } + return +} +``` +### **TypeScript** + +```ts +function numberOfSets(n: number, maxDistance: number, roads: number[][]): number { + let ans = 0; + for (let mask = 0; mask < 1 << n; ++mask) { + const g: number[][] = Array.from({ length: n }, () => Array(n).fill(Infinity)); + for (const [u, v, w] of roads) { + if ((mask >> u) & 1 && (mask >> v) & 1) { + g[u][v] = Math.min(g[u][v], w); + g[v][u] = Math.min(g[v][u], w); + } + } + for (let k = 0; k < n; ++k) { + if ((mask >> k) & 1) { + g[k][k] = 0; + for (let i = 0; i < n; ++i) { + for (let j = 0; j < n; ++j) { + g[i][j] = Math.min(g[i][j], g[i][k] + g[k][j]); + } + } + } + } + let ok = 1; + for (let i = 0; i < n && ok; ++i) { + for (let j = 0; j < n && ok; ++j) { + if ((mask >> i) & 1 && (mask >> j) & 1 && g[i][j] > maxDistance) { + ok = 0; + } + } + } + ans += ok; + } + return ans; +} ``` ### **...** diff --git a/solution/2900-2999/2959.Number of Possible Sets of Closing Branches/Solution.cpp b/solution/2900-2999/2959.Number of Possible Sets of Closing Branches/Solution.cpp new file mode 100644 index 0000000000000..ccf9b66944375 --- /dev/null +++ b/solution/2900-2999/2959.Number of Possible Sets of Closing Branches/Solution.cpp @@ -0,0 +1,37 @@ +class Solution { +public: + int numberOfSets(int n, int maxDistance, vector>& roads) { + int ans = 0; + for (int mask = 0; mask < 1 << n; ++mask) { + int g[n][n]; + memset(g, 0x3f, sizeof(g)); + for (auto& e : roads) { + int u = e[0], v = e[1], w = e[2]; + if ((mask >> u & 1) & (mask >> v & 1)) { + g[u][v] = min(g[u][v], w); + g[v][u] = min(g[v][u], w); + } + } + for (int k = 0; k < n; ++k) { + if (mask >> k & 1) { + g[k][k] = 0; + for (int i = 0; i < n; ++i) { + for (int j = 0; j < n; ++j) { + g[i][j] = min(g[i][j], g[i][k] + g[k][j]); + } + } + } + } + int ok = 1; + for (int i = 0; i < n && ok == 1; ++i) { + for (int j = 0; j < n && ok == 1; ++j) { + if ((mask >> i & 1) & (mask >> j & 1) && g[i][j] > maxDistance) { + ok = 0; + } + } + } + ans += ok; + } + return ans; + } +}; \ No newline at end of file diff --git a/solution/2900-2999/2959.Number of Possible Sets of Closing Branches/Solution.go b/solution/2900-2999/2959.Number of Possible Sets of Closing Branches/Solution.go new file mode 100644 index 0000000000000..ee20f387dde2d --- /dev/null +++ b/solution/2900-2999/2959.Number of Possible Sets of Closing Branches/Solution.go @@ -0,0 +1,38 @@ +func numberOfSets(n int, maxDistance int, roads [][]int) (ans int) { + for mask := 0; mask < 1<>u&1 == 1 && mask>>v&1 == 1 { + g[u][v] = min(g[u][v], w) + g[v][u] = min(g[v][u], w) + } + } + for k := 0; k < n; k++ { + if mask>>k&1 == 1 { + g[k][k] = 0 + for i := 0; i < n; i++ { + for j := 0; j < n; j++ { + g[i][j] = min(g[i][j], g[i][k]+g[k][j]) + } + } + } + } + ok := 1 + for i := 0; i < n && ok == 1; i++ { + for j := 0; j < n && ok == 1; j++ { + if mask>>i&1 == 1 && mask>>j&1 == 1 && g[i][j] > maxDistance { + ok = 0 + } + } + } + ans += ok + } + return +} \ No newline at end of file diff --git a/solution/2900-2999/2959.Number of Possible Sets of Closing Branches/Solution.java b/solution/2900-2999/2959.Number of Possible Sets of Closing Branches/Solution.java new file mode 100644 index 0000000000000..4cfe7461b4a4e --- /dev/null +++ b/solution/2900-2999/2959.Number of Possible Sets of Closing Branches/Solution.java @@ -0,0 +1,40 @@ +class Solution { + public int numberOfSets(int n, int maxDistance, int[][] roads) { + int ans = 0; + for (int mask = 0; mask < 1 << n; ++mask) { + int[][] g = new int[n][n]; + for (var e : g) { + Arrays.fill(e, 1 << 29); + } + for (var e : roads) { + int u = e[0], v = e[1], w = e[2]; + if ((mask >> u & 1) == 1 && (mask >> v & 1) == 1) { + g[u][v] = Math.min(g[u][v], w); + g[v][u] = Math.min(g[v][u], w); + } + } + for (int k = 0; k < n; ++k) { + if ((mask >> k & 1) == 1) { + g[k][k] = 0; + for (int i = 0; i < n; ++i) { + for (int j = 0; j < n; ++j) { + g[i][j] = Math.min(g[i][j], g[i][k] + g[k][j]); + } + } + } + } + int ok = 1; + for (int i = 0; i < n && ok == 1; ++i) { + for (int j = 0; j < n && ok == 1; ++j) { + if ((mask >> i & 1) == 1 && (mask >> j & 1) == 1) { + if (g[i][j] > maxDistance) { + ok = 0; + } + } + } + } + ans += ok; + } + return ans; + } +} \ No newline at end of file diff --git a/solution/2900-2999/2959.Number of Possible Sets of Closing Branches/Solution.py b/solution/2900-2999/2959.Number of Possible Sets of Closing Branches/Solution.py new file mode 100644 index 0000000000000..4f230d896c338 --- /dev/null +++ b/solution/2900-2999/2959.Number of Possible Sets of Closing Branches/Solution.py @@ -0,0 +1,25 @@ +class Solution: + def numberOfSets(self, n: int, maxDistance: int, roads: List[List[int]]) -> int: + ans = 0 + for mask in range(1 << n): + g = [[inf] * n for _ in range(n)] + for u, v, w in roads: + if mask >> u & 1 and mask > v & 1: + g[u][v] = min(g[u][v], w) + g[v][u] = min(g[v][u], w) + for k in range(n): + if mask >> k & 1: + g[k][k] = 0 + for i in range(n): + for j in range(n): + # g[i][j] = min(g[i][j], g[i][k] + g[k][j]) + if g[i][k] + g[k][j] < g[i][j]: + g[i][j] = g[i][k] + g[k][j] + if all( + g[i][j] <= maxDistance + for i in range(n) + for j in range(n) + if mask >> i & 1 and mask >> j & 1 + ): + ans += 1 + return ans diff --git a/solution/2900-2999/2959.Number of Possible Sets of Closing Branches/Solution.ts b/solution/2900-2999/2959.Number of Possible Sets of Closing Branches/Solution.ts new file mode 100644 index 0000000000000..4031ece719c68 --- /dev/null +++ b/solution/2900-2999/2959.Number of Possible Sets of Closing Branches/Solution.ts @@ -0,0 +1,32 @@ +function numberOfSets(n: number, maxDistance: number, roads: number[][]): number { + let ans = 0; + for (let mask = 0; mask < 1 << n; ++mask) { + const g: number[][] = Array.from({ length: n }, () => Array(n).fill(Infinity)); + for (const [u, v, w] of roads) { + if ((mask >> u) & 1 && (mask >> v) & 1) { + g[u][v] = Math.min(g[u][v], w); + g[v][u] = Math.min(g[v][u], w); + } + } + for (let k = 0; k < n; ++k) { + if ((mask >> k) & 1) { + g[k][k] = 0; + for (let i = 0; i < n; ++i) { + for (let j = 0; j < n; ++j) { + g[i][j] = Math.min(g[i][j], g[i][k] + g[k][j]); + } + } + } + } + let ok = 1; + for (let i = 0; i < n && ok; ++i) { + for (let j = 0; j < n && ok; ++j) { + if ((mask >> i) & 1 && (mask >> j) & 1 && g[i][j] > maxDistance) { + ok = 0; + } + } + } + ans += ok; + } + return ans; +} From a242d2f900700cfc05fdcc0184cff5e2b2928fb4 Mon Sep 17 00:00:00 2001 From: Libin YANG Date: Mon, 11 Dec 2023 19:00:35 +0800 Subject: [PATCH 3/5] feat: add solutions to lc problems: No.2960~2963 (#2083) * No.2960.Count Tested Devices After Test Operations * No.2961.Double Modular Exponentiation * No.2962.Count Subarrays Where Max Element Appears at Least K Times * No.2963.Count the Number of Good Partitions --- .../README.md | 68 ++++++++- .../README_EN.md | 68 ++++++++- .../Solution.cpp | 13 ++ .../Solution.go | 9 ++ .../Solution.java | 12 ++ .../Solution.py | 7 + .../Solution.ts | 10 ++ .../README.md | 107 +++++++++++++- .../README_EN.md | 107 +++++++++++++- .../Solution.cpp | 24 ++++ .../Solution.go | 19 +++ .../Solution.java | 24 ++++ .../Solution.py | 7 + .../Solution.ts | 20 +++ .../README.md | 107 +++++++++++++- .../README_EN.md | 107 +++++++++++++- .../Solution.cpp | 20 +++ .../Solution.go | 20 +++ .../Solution.java | 19 +++ .../Solution.py | 14 ++ .../Solution.ts | 17 +++ .../README.md | 134 +++++++++++++++++- .../README_EN.md | 134 +++++++++++++++++- .../Solution.cpp | 27 ++++ .../Solution.go | 25 ++++ .../Solution.java | 28 ++++ .../Solution.py | 9 ++ .../Solution.ts | 26 ++++ solution/config.py | 1 + 29 files changed, 1155 insertions(+), 28 deletions(-) create mode 100644 solution/2900-2999/2960.Count Tested Devices After Test Operations/Solution.cpp create mode 100644 solution/2900-2999/2960.Count Tested Devices After Test Operations/Solution.go create mode 100644 solution/2900-2999/2960.Count Tested Devices After Test Operations/Solution.java create mode 100644 solution/2900-2999/2960.Count Tested Devices After Test Operations/Solution.py create mode 100644 solution/2900-2999/2960.Count Tested Devices After Test Operations/Solution.ts create mode 100644 solution/2900-2999/2961.Double Modular Exponentiation/Solution.cpp create mode 100644 solution/2900-2999/2961.Double Modular Exponentiation/Solution.go create mode 100644 solution/2900-2999/2961.Double Modular Exponentiation/Solution.java create mode 100644 solution/2900-2999/2961.Double Modular Exponentiation/Solution.py create mode 100644 solution/2900-2999/2961.Double Modular Exponentiation/Solution.ts create mode 100644 solution/2900-2999/2962.Count Subarrays Where Max Element Appears at Least K Times/Solution.cpp create mode 100644 solution/2900-2999/2962.Count Subarrays Where Max Element Appears at Least K Times/Solution.go create mode 100644 solution/2900-2999/2962.Count Subarrays Where Max Element Appears at Least K Times/Solution.java create mode 100644 solution/2900-2999/2962.Count Subarrays Where Max Element Appears at Least K Times/Solution.py create mode 100644 solution/2900-2999/2962.Count Subarrays Where Max Element Appears at Least K Times/Solution.ts create mode 100644 solution/2900-2999/2963.Count the Number of Good Partitions/Solution.cpp create mode 100644 solution/2900-2999/2963.Count the Number of Good Partitions/Solution.go create mode 100644 solution/2900-2999/2963.Count the Number of Good Partitions/Solution.java create mode 100644 solution/2900-2999/2963.Count the Number of Good Partitions/Solution.py create mode 100644 solution/2900-2999/2963.Count the Number of Good Partitions/Solution.ts diff --git a/solution/2900-2999/2960.Count Tested Devices After Test Operations/README.md b/solution/2900-2999/2960.Count Tested Devices After Test Operations/README.md index 7735b6d7f5b43..9aa3117e069cb 100644 --- a/solution/2900-2999/2960.Count Tested Devices After Test Operations/README.md +++ b/solution/2900-2999/2960.Count Tested Devices After Test Operations/README.md @@ -12,7 +12,6 @@
  • 如果 batteryPercentages[i] 大于 0: -
    • 增加 已测试设备的计数。
    • 将下标在 [i + 1, n - 1] 的所有设备的电池百分比减少 1,确保它们的电池百分比 不会低于 0 ,即 batteryPercentages[j] = max(0, batteryPercentages[j] - 1)
    • @@ -20,7 +19,6 @@
  • 否则,移动到下一个设备而不执行任何测试。
  • -

返回一个整数,表示按顺序执行测试操作后 已测试设备 的数量。

@@ -66,6 +64,14 @@ +**方法一:模拟** + +假设我们当前已测试的设备数量为 $ans$,如果当测试新的一台设备 $i$ 时,它的剩余电量为 $\max(0, batteryPercentages[i] - ans)$,如果剩余电量大于 $0$,则说明这台设备可以进行测试,此时我们需要将 $ans$ 增加 $1$。 + +最后返回 $ans$ 即可。 + +时间复杂度 $O(n)$,其中 $n$ 为数组长度。空间复杂度 $O(1)$。 + ### **Python3** @@ -73,7 +79,13 @@ ```python - +class Solution: + def countTestedDevices(self, batteryPercentages: List[int]) -> int: + ans = 0 + for x in batteryPercentages: + x -= ans + ans += x > 0 + return ans ``` ### **Java** @@ -81,19 +93,65 @@ ```java - +class Solution { + public int countTestedDevices(int[] batteryPercentages) { + int ans = 0; + for (int x : batteryPercentages) { + x -= ans; + if (x > 0) { + ++ans; + } + } + return ans; + } +} ``` ### **C++** ```cpp - +class Solution { +public: + int countTestedDevices(vector& batteryPercentages) { + int ans = 0; + for (int x : batteryPercentages) { + x -= ans; + if (x > 0) { + ++ans; + } + } + return ans; + } +}; ``` ### **Go** ```go +func countTestedDevices(batteryPercentages []int) (ans int) { + for _, x := range batteryPercentages { + x -= ans + if x > 0 { + ans++ + } + } + return +} +``` +### **TypeScript** + +```ts +function countTestedDevices(batteryPercentages: number[]): number { + let ans = 0; + for (let x of batteryPercentages) { + x -= ans; + if (x > 0) { + ++ans; + } + } + return ans; +} ``` ### **...** diff --git a/solution/2900-2999/2960.Count Tested Devices After Test Operations/README_EN.md b/solution/2900-2999/2960.Count Tested Devices After Test Operations/README_EN.md index f407a1e3e3ef6..07b6b8fbce357 100644 --- a/solution/2900-2999/2960.Count Tested Devices After Test Operations/README_EN.md +++ b/solution/2900-2999/2960.Count Tested Devices After Test Operations/README_EN.md @@ -10,7 +10,6 @@
  • If batteryPercentages[i] is greater than 0: -
    • Increment the count of tested devices.
    • Decrease the battery percentage of all devices with indices j in the range [i + 1, n - 1] by 1, ensuring their battery percentage never goes below 0, i.e, batteryPercentages[j] = max(0, batteryPercentages[j] - 1).
    • @@ -18,7 +17,6 @@
  • Otherwise, move to the next device without performing any test.
  • -

Return an integer denoting the number of devices that will be tested after performing the test operations in order.

@@ -60,30 +58,90 @@ So, the answer is 2. ## Solutions +**Solution 1: Simulation** + +Assume that the current number of devices we have tested is $ans$. When testing a new device $i$, its remaining battery is $\max(0, batteryPercentages[i] - ans)$. If the remaining battery is greater than $0$, it means this device can be tested, and we need to increase $ans$ by $1$. + +Finally, return $ans$. + +The time complexity is $O(n)$, where $n$ is the length of the array. The space complexity is $O(1)$. + ### **Python3** ```python - +class Solution: + def countTestedDevices(self, batteryPercentages: List[int]) -> int: + ans = 0 + for x in batteryPercentages: + x -= ans + ans += x > 0 + return ans ``` ### **Java** ```java - +class Solution { + public int countTestedDevices(int[] batteryPercentages) { + int ans = 0; + for (int x : batteryPercentages) { + x -= ans; + if (x > 0) { + ++ans; + } + } + return ans; + } +} ``` ### **C++** ```cpp - +class Solution { +public: + int countTestedDevices(vector& batteryPercentages) { + int ans = 0; + for (int x : batteryPercentages) { + x -= ans; + if (x > 0) { + ++ans; + } + } + return ans; + } +}; ``` ### **Go** ```go +func countTestedDevices(batteryPercentages []int) (ans int) { + for _, x := range batteryPercentages { + x -= ans + if x > 0 { + ans++ + } + } + return +} +``` +### **TypeScript** + +```ts +function countTestedDevices(batteryPercentages: number[]): number { + let ans = 0; + for (let x of batteryPercentages) { + x -= ans; + if (x > 0) { + ++ans; + } + } + return ans; +} ``` ### **...** diff --git a/solution/2900-2999/2960.Count Tested Devices After Test Operations/Solution.cpp b/solution/2900-2999/2960.Count Tested Devices After Test Operations/Solution.cpp new file mode 100644 index 0000000000000..4d0a559c365ec --- /dev/null +++ b/solution/2900-2999/2960.Count Tested Devices After Test Operations/Solution.cpp @@ -0,0 +1,13 @@ +class Solution { +public: + int countTestedDevices(vector& batteryPercentages) { + int ans = 0; + for (int x : batteryPercentages) { + x -= ans; + if (x > 0) { + ++ans; + } + } + return ans; + } +}; \ No newline at end of file diff --git a/solution/2900-2999/2960.Count Tested Devices After Test Operations/Solution.go b/solution/2900-2999/2960.Count Tested Devices After Test Operations/Solution.go new file mode 100644 index 0000000000000..6922458f5d15c --- /dev/null +++ b/solution/2900-2999/2960.Count Tested Devices After Test Operations/Solution.go @@ -0,0 +1,9 @@ +func countTestedDevices(batteryPercentages []int) (ans int) { + for _, x := range batteryPercentages { + x -= ans + if x > 0 { + ans++ + } + } + return +} \ No newline at end of file diff --git a/solution/2900-2999/2960.Count Tested Devices After Test Operations/Solution.java b/solution/2900-2999/2960.Count Tested Devices After Test Operations/Solution.java new file mode 100644 index 0000000000000..93ac3c105b2f7 --- /dev/null +++ b/solution/2900-2999/2960.Count Tested Devices After Test Operations/Solution.java @@ -0,0 +1,12 @@ +class Solution { + public int countTestedDevices(int[] batteryPercentages) { + int ans = 0; + for (int x : batteryPercentages) { + x -= ans; + if (x > 0) { + ++ans; + } + } + return ans; + } +} \ No newline at end of file diff --git a/solution/2900-2999/2960.Count Tested Devices After Test Operations/Solution.py b/solution/2900-2999/2960.Count Tested Devices After Test Operations/Solution.py new file mode 100644 index 0000000000000..bf95721ce9c6e --- /dev/null +++ b/solution/2900-2999/2960.Count Tested Devices After Test Operations/Solution.py @@ -0,0 +1,7 @@ +class Solution: + def countTestedDevices(self, batteryPercentages: List[int]) -> int: + ans = 0 + for x in batteryPercentages: + x -= ans + ans += x > 0 + return ans diff --git a/solution/2900-2999/2960.Count Tested Devices After Test Operations/Solution.ts b/solution/2900-2999/2960.Count Tested Devices After Test Operations/Solution.ts new file mode 100644 index 0000000000000..b986a983cac6a --- /dev/null +++ b/solution/2900-2999/2960.Count Tested Devices After Test Operations/Solution.ts @@ -0,0 +1,10 @@ +function countTestedDevices(batteryPercentages: number[]): number { + let ans = 0; + for (let x of batteryPercentages) { + x -= ans; + if (x > 0) { + ++ans; + } + } + return ans; +} diff --git a/solution/2900-2999/2961.Double Modular Exponentiation/README.md b/solution/2900-2999/2961.Double Modular Exponentiation/README.md index b5899ce2216fa..4baff00312a7e 100644 --- a/solution/2900-2999/2961.Double Modular Exponentiation/README.md +++ b/solution/2900-2999/2961.Double Modular Exponentiation/README.md @@ -56,6 +56,12 @@ +**方法一:模拟 + 快速幂** + +我们直接根据题目描述模拟即可。对于幂运算取模,我们可以使用快速幂来加速运算。 + +时间复杂度 $O(n \times \log M)$,其中 $n$ 为数组 $variables$ 的长度;而 $M$ 为 $b_i$ 和 $c_i$ 中的最大值,本题中 $M \le 10^3$。空间复杂度 $O(1)$。 + ### **Python3** @@ -63,7 +69,13 @@ ```python - +class Solution: + def getGoodIndices(self, variables: List[List[int]], target: int) -> List[int]: + return [ + i + for i, (a, b, c, m) in enumerate(variables) + if pow(pow(a, b, 10), c, m) == target + ] ``` ### **Java** @@ -71,19 +83,108 @@ ```java - +class Solution { + public List getGoodIndices(int[][] variables, int target) { + List ans = new ArrayList<>(); + for (int i = 0; i < variables.length; ++i) { + var e = variables[i]; + int a = e[0], b = e[1], c = e[2], m = e[3]; + if (qpow(qpow(a, b, 10), c, m) == target) { + ans.add(i); + } + } + return ans; + } + + private int qpow(long a, int n, int mod) { + long ans = 1; + for (; n > 0; n >>= 1) { + if ((n & 1) == 1) { + ans = ans * a % mod; + } + a = a * a % mod; + } + return (int) ans; + } +} ``` ### **C++** ```cpp - +class Solution { +public: + vector getGoodIndices(vector>& variables, int target) { + vector ans; + auto qpow = [&](long long a, int n, int mod) { + long long ans = 1; + for (; n; n >>= 1) { + if (n & 1) { + ans = ans * a % mod; + } + a = a * a % mod; + } + return (int) ans; + }; + for (int i = 0; i < variables.size(); ++i) { + auto e = variables[i]; + int a = e[0], b = e[1], c = e[2], m = e[3]; + if (qpow(qpow(a, b, 10), c, m) == target) { + ans.push_back(i); + } + } + return ans; + } +}; ``` ### **Go** ```go +func getGoodIndices(variables [][]int, target int) (ans []int) { + qpow := func(a, n, mod int) int { + ans := 1 + for ; n > 0; n >>= 1 { + if n&1 == 1 { + ans = ans * a % mod + } + a = a * a % mod + } + return ans + } + for i, e := range variables { + a, b, c, m := e[0], e[1], e[2], e[3] + if qpow(qpow(a, b, 10), c, m) == target { + ans = append(ans, i) + } + } + return +} +``` +### **TypeScript** + +```ts +function getGoodIndices(variables: number[][], target: number): number[] { + const qpow = (a: number, n: number, mod: number) => { + let ans = 1; + for (; n; n >>= 1) { + if (n & 1) { + ans = Number((BigInt(ans) * BigInt(a)) % BigInt(mod)); + } + a = Number((BigInt(a) * BigInt(a)) % BigInt(mod)); + } + return ans; + }; + const ans: number[] = []; + for (let i = 0; i < variables.length; ++i) { + const [a, b, c, m] = variables[i]; + if (qpow(qpow(a, b, 10), c, m) === target) { + ans.push(i); + } + } + return ans; +} ``` ### **...** diff --git a/solution/2900-2999/2961.Double Modular Exponentiation/README_EN.md b/solution/2900-2999/2961.Double Modular Exponentiation/README_EN.md index 1023b087ec946..a6f1c9afb311f 100644 --- a/solution/2900-2999/2961.Double Modular Exponentiation/README_EN.md +++ b/solution/2900-2999/2961.Double Modular Exponentiation/README_EN.md @@ -50,30 +50,131 @@ Therefore we return [] as the answer. ## Solutions +**Solution 1: Simulation + Fast Power** + +We can directly simulate according to the problem description. For the power operation modulo, we can use the fast power method to speed up the calculation. + +The time complexity is $O(n \times \log M)$, where $n$ is the length of the array $variables$; and $M$ is the maximum value in $b_i$ and $c_i$, in this problem $M \le 10^3$. The space complexity is $O(1)$. + ### **Python3** ```python - +class Solution: + def getGoodIndices(self, variables: List[List[int]], target: int) -> List[int]: + return [ + i + for i, (a, b, c, m) in enumerate(variables) + if pow(pow(a, b, 10), c, m) == target + ] ``` ### **Java** ```java - +class Solution { + public List getGoodIndices(int[][] variables, int target) { + List ans = new ArrayList<>(); + for (int i = 0; i < variables.length; ++i) { + var e = variables[i]; + int a = e[0], b = e[1], c = e[2], m = e[3]; + if (qpow(qpow(a, b, 10), c, m) == target) { + ans.add(i); + } + } + return ans; + } + + private int qpow(long a, int n, int mod) { + long ans = 1; + for (; n > 0; n >>= 1) { + if ((n & 1) == 1) { + ans = ans * a % mod; + } + a = a * a % mod; + } + return (int) ans; + } +} ``` ### **C++** ```cpp - +class Solution { +public: + vector getGoodIndices(vector>& variables, int target) { + vector ans; + auto qpow = [&](long long a, int n, int mod) { + long long ans = 1; + for (; n; n >>= 1) { + if (n & 1) { + ans = ans * a % mod; + } + a = a * a % mod; + } + return (int) ans; + }; + for (int i = 0; i < variables.size(); ++i) { + auto e = variables[i]; + int a = e[0], b = e[1], c = e[2], m = e[3]; + if (qpow(qpow(a, b, 10), c, m) == target) { + ans.push_back(i); + } + } + return ans; + } +}; ``` ### **Go** ```go +func getGoodIndices(variables [][]int, target int) (ans []int) { + qpow := func(a, n, mod int) int { + ans := 1 + for ; n > 0; n >>= 1 { + if n&1 == 1 { + ans = ans * a % mod + } + a = a * a % mod + } + return ans + } + for i, e := range variables { + a, b, c, m := e[0], e[1], e[2], e[3] + if qpow(qpow(a, b, 10), c, m) == target { + ans = append(ans, i) + } + } + return +} +``` +### **TypeScript** + +```ts +function getGoodIndices(variables: number[][], target: number): number[] { + const qpow = (a: number, n: number, mod: number) => { + let ans = 1; + for (; n; n >>= 1) { + if (n & 1) { + ans = Number((BigInt(ans) * BigInt(a)) % BigInt(mod)); + } + a = Number((BigInt(a) * BigInt(a)) % BigInt(mod)); + } + return ans; + }; + const ans: number[] = []; + for (let i = 0; i < variables.length; ++i) { + const [a, b, c, m] = variables[i]; + if (qpow(qpow(a, b, 10), c, m) === target) { + ans.push(i); + } + } + return ans; +} ``` ### **...** diff --git a/solution/2900-2999/2961.Double Modular Exponentiation/Solution.cpp b/solution/2900-2999/2961.Double Modular Exponentiation/Solution.cpp new file mode 100644 index 0000000000000..369f5b75127b8 --- /dev/null +++ b/solution/2900-2999/2961.Double Modular Exponentiation/Solution.cpp @@ -0,0 +1,24 @@ +class Solution { +public: + vector getGoodIndices(vector>& variables, int target) { + vector ans; + auto qpow = [&](long long a, int n, int mod) { + long long ans = 1; + for (; n; n >>= 1) { + if (n & 1) { + ans = ans * a % mod; + } + a = a * a % mod; + } + return (int) ans; + }; + for (int i = 0; i < variables.size(); ++i) { + auto e = variables[i]; + int a = e[0], b = e[1], c = e[2], m = e[3]; + if (qpow(qpow(a, b, 10), c, m) == target) { + ans.push_back(i); + } + } + return ans; + } +}; \ No newline at end of file diff --git a/solution/2900-2999/2961.Double Modular Exponentiation/Solution.go b/solution/2900-2999/2961.Double Modular Exponentiation/Solution.go new file mode 100644 index 0000000000000..483e2904ed7d5 --- /dev/null +++ b/solution/2900-2999/2961.Double Modular Exponentiation/Solution.go @@ -0,0 +1,19 @@ +func getGoodIndices(variables [][]int, target int) (ans []int) { + qpow := func(a, n, mod int) int { + ans := 1 + for ; n > 0; n >>= 1 { + if n&1 == 1 { + ans = ans * a % mod + } + a = a * a % mod + } + return ans + } + for i, e := range variables { + a, b, c, m := e[0], e[1], e[2], e[3] + if qpow(qpow(a, b, 10), c, m) == target { + ans = append(ans, i) + } + } + return +} \ No newline at end of file diff --git a/solution/2900-2999/2961.Double Modular Exponentiation/Solution.java b/solution/2900-2999/2961.Double Modular Exponentiation/Solution.java new file mode 100644 index 0000000000000..7618aecd76480 --- /dev/null +++ b/solution/2900-2999/2961.Double Modular Exponentiation/Solution.java @@ -0,0 +1,24 @@ +class Solution { + public List getGoodIndices(int[][] variables, int target) { + List ans = new ArrayList<>(); + for (int i = 0; i < variables.length; ++i) { + var e = variables[i]; + int a = e[0], b = e[1], c = e[2], m = e[3]; + if (qpow(qpow(a, b, 10), c, m) == target) { + ans.add(i); + } + } + return ans; + } + + private int qpow(long a, int n, int mod) { + long ans = 1; + for (; n > 0; n >>= 1) { + if ((n & 1) == 1) { + ans = ans * a % mod; + } + a = a * a % mod; + } + return (int) ans; + } +} \ No newline at end of file diff --git a/solution/2900-2999/2961.Double Modular Exponentiation/Solution.py b/solution/2900-2999/2961.Double Modular Exponentiation/Solution.py new file mode 100644 index 0000000000000..03c4cb37dbb95 --- /dev/null +++ b/solution/2900-2999/2961.Double Modular Exponentiation/Solution.py @@ -0,0 +1,7 @@ +class Solution: + def getGoodIndices(self, variables: List[List[int]], target: int) -> List[int]: + return [ + i + for i, (a, b, c, m) in enumerate(variables) + if pow(pow(a, b, 10), c, m) == target + ] diff --git a/solution/2900-2999/2961.Double Modular Exponentiation/Solution.ts b/solution/2900-2999/2961.Double Modular Exponentiation/Solution.ts new file mode 100644 index 0000000000000..f82fcd4e310b8 --- /dev/null +++ b/solution/2900-2999/2961.Double Modular Exponentiation/Solution.ts @@ -0,0 +1,20 @@ +function getGoodIndices(variables: number[][], target: number): number[] { + const qpow = (a: number, n: number, mod: number) => { + let ans = 1; + for (; n; n >>= 1) { + if (n & 1) { + ans = Number((BigInt(ans) * BigInt(a)) % BigInt(mod)); + } + a = Number((BigInt(a) * BigInt(a)) % BigInt(mod)); + } + return ans; + }; + const ans: number[] = []; + for (let i = 0; i < variables.length; ++i) { + const [a, b, c, m] = variables[i]; + if (qpow(qpow(a, b, 10), c, m) === target) { + ans.push(i); + } + } + return ans; +} diff --git a/solution/2900-2999/2962.Count Subarrays Where Max Element Appears at Least K Times/README.md b/solution/2900-2999/2962.Count Subarrays Where Max Element Appears at Least K Times/README.md index e468813584c23..92b2fdaa09b57 100644 --- a/solution/2900-2999/2962.Count Subarrays Where Max Element Appears at Least K Times/README.md +++ b/solution/2900-2999/2962.Count Subarrays Where Max Element Appears at Least K Times/README.md @@ -44,6 +44,16 @@ +**方法一:双指针** + +不妨记数组中的最大值为 $mx$。 + +我们用两个指针 $i$ 和 $j$ 维护一个滑动窗口,使得 $[i, j)$ 之间的子数组中,有 $k$ 个元素等于 $mx$。如果我们固定左端点 $i$,那么所有大于等于 $j-1$ 的右端点都满足条件,一共有 $n - (j - 1)$ 个。 + +因此,我们枚举左端点 $i$,用指针 $j$ 维护右端点,用一个变量 $cnt$ 记录当前窗口中等于 $mx$ 的元素个数,当 $cnt$ 大于等于 $k$ 时,我们就找到了满足条件的子数组,将答案增加 $n - (j - 1)$。然后我们更新 $cnt$,继续枚举下一个左端点。 + +时间复杂度 $O(n)$,其中 $n$ 是数组 $nums$ 的长度。空间复杂度 $O(1)$。 + ### **Python3** @@ -51,7 +61,20 @@ ```python - +class Solution: + def countSubarrays(self, nums: List[int], k: int) -> int: + mx = max(nums) + n = len(nums) + ans = cnt = j = 0 + for x in nums: + while j < n and cnt < k: + cnt += nums[j] == mx + j += 1 + if cnt < k: + break + ans += n - j + 1 + cnt -= x == mx + return ans ``` ### **Java** @@ -59,19 +82,97 @@ ```java - +class Solution { + public long countSubarrays(int[] nums, int k) { + int mx = Arrays.stream(nums).max().getAsInt(); + int n = nums.length; + long ans = 0; + int cnt = 0, j = 0; + for (int x : nums) { + while (j < n && cnt < k) { + cnt += nums[j++] == mx ? 1 : 0; + } + if (cnt < k) { + break; + } + ans += n - j + 1; + cnt -= x == mx ? 1 : 0; + } + return ans; + } +} ``` ### **C++** ```cpp - +class Solution { +public: + long long countSubarrays(vector& nums, int k) { + int mx = *max_element(nums.begin(), nums.end()); + int n = nums.size(); + long long ans = 0; + int cnt = 0, j = 0; + for (int x : nums) { + while (j < n && cnt < k) { + cnt += nums[j++] == mx; + } + if (cnt < k) { + break; + } + ans += n - j + 1; + cnt -= x == mx; + } + return ans; + } +}; ``` ### **Go** ```go +func countSubarrays(nums []int, k int) (ans int64) { + mx := slices.Max(nums) + n := len(nums) + cnt, j := 0, 0 + for _, x := range nums { + for ; j < n && cnt < k; j++ { + if nums[j] == mx { + cnt++ + } + } + if cnt < k { + break + } + ans += int64(n - j + 1) + if x == mx { + cnt-- + } + } + return +} +``` +### **TypeScript** + +```ts +function countSubarrays(nums: number[], k: number): number { + const mx = Math.max(...nums); + const n = nums.length; + let [cnt, j] = [0, 0]; + let ans = 0; + for (const x of nums) { + for (; j < n && cnt < k; ++j) { + cnt += nums[j] === mx ? 1 : 0; + } + if (cnt < k) { + break; + } + ans += n - j + 1; + cnt -= x === mx ? 1 : 0; + } + return ans; +} ``` ### **...** diff --git a/solution/2900-2999/2962.Count Subarrays Where Max Element Appears at Least K Times/README_EN.md b/solution/2900-2999/2962.Count Subarrays Where Max Element Appears at Least K Times/README_EN.md index eeb556abf8bbb..4847ef968acb8 100644 --- a/solution/2900-2999/2962.Count Subarrays Where Max Element Appears at Least K Times/README_EN.md +++ b/solution/2900-2999/2962.Count Subarrays Where Max Element Appears at Least K Times/README_EN.md @@ -38,30 +38,131 @@ ## Solutions +**Solution 1: Two Pointers** + +Let's denote the maximum value in the array as $mx$. + +We use two pointers $i$ and $j$ to maintain a sliding window, such that in the subarray between $[i, j)$, there are $k$ elements equal to $mx$. If we fix the left endpoint $i$, then all right endpoints greater than or equal to $j-1$ meet the condition, totaling $n - (j - 1)$. + +Therefore, we enumerate the left endpoint $i$, use the pointer $j$ to maintain the right endpoint, use a variable $cnt$ to record the number of elements equal to $mx$ in the current window. When $cnt$ is greater than or equal to $k$, we have found a subarray that meets the condition, and we increase the answer by $n - (j - 1)$. Then we update $cnt$ and continue to enumerate the next left endpoint. + +The time complexity is $O(n)$, where $n$ is the length of the array $nums$. The space complexity is $O(1)$. + ### **Python3** ```python - +class Solution: + def countSubarrays(self, nums: List[int], k: int) -> int: + mx = max(nums) + n = len(nums) + ans = cnt = j = 0 + for x in nums: + while j < n and cnt < k: + cnt += nums[j] == mx + j += 1 + if cnt < k: + break + ans += n - j + 1 + cnt -= x == mx + return ans ``` ### **Java** ```java - +class Solution { + public long countSubarrays(int[] nums, int k) { + int mx = Arrays.stream(nums).max().getAsInt(); + int n = nums.length; + long ans = 0; + int cnt = 0, j = 0; + for (int x : nums) { + while (j < n && cnt < k) { + cnt += nums[j++] == mx ? 1 : 0; + } + if (cnt < k) { + break; + } + ans += n - j + 1; + cnt -= x == mx ? 1 : 0; + } + return ans; + } +} ``` ### **C++** ```cpp - +class Solution { +public: + long long countSubarrays(vector& nums, int k) { + int mx = *max_element(nums.begin(), nums.end()); + int n = nums.size(); + long long ans = 0; + int cnt = 0, j = 0; + for (int x : nums) { + while (j < n && cnt < k) { + cnt += nums[j++] == mx; + } + if (cnt < k) { + break; + } + ans += n - j + 1; + cnt -= x == mx; + } + return ans; + } +}; ``` ### **Go** ```go +func countSubarrays(nums []int, k int) (ans int64) { + mx := slices.Max(nums) + n := len(nums) + cnt, j := 0, 0 + for _, x := range nums { + for ; j < n && cnt < k; j++ { + if nums[j] == mx { + cnt++ + } + } + if cnt < k { + break + } + ans += int64(n - j + 1) + if x == mx { + cnt-- + } + } + return +} +``` +### **TypeScript** + +```ts +function countSubarrays(nums: number[], k: number): number { + const mx = Math.max(...nums); + const n = nums.length; + let [cnt, j] = [0, 0]; + let ans = 0; + for (const x of nums) { + for (; j < n && cnt < k; ++j) { + cnt += nums[j] === mx ? 1 : 0; + } + if (cnt < k) { + break; + } + ans += n - j + 1; + cnt -= x === mx ? 1 : 0; + } + return ans; +} ``` ### **...** diff --git a/solution/2900-2999/2962.Count Subarrays Where Max Element Appears at Least K Times/Solution.cpp b/solution/2900-2999/2962.Count Subarrays Where Max Element Appears at Least K Times/Solution.cpp new file mode 100644 index 0000000000000..c3b64b9cca4a9 --- /dev/null +++ b/solution/2900-2999/2962.Count Subarrays Where Max Element Appears at Least K Times/Solution.cpp @@ -0,0 +1,20 @@ +class Solution { +public: + long long countSubarrays(vector& nums, int k) { + int mx = *max_element(nums.begin(), nums.end()); + int n = nums.size(); + long long ans = 0; + int cnt = 0, j = 0; + for (int x : nums) { + while (j < n && cnt < k) { + cnt += nums[j++] == mx; + } + if (cnt < k) { + break; + } + ans += n - j + 1; + cnt -= x == mx; + } + return ans; + } +}; \ No newline at end of file diff --git a/solution/2900-2999/2962.Count Subarrays Where Max Element Appears at Least K Times/Solution.go b/solution/2900-2999/2962.Count Subarrays Where Max Element Appears at Least K Times/Solution.go new file mode 100644 index 0000000000000..7f4030888cdb8 --- /dev/null +++ b/solution/2900-2999/2962.Count Subarrays Where Max Element Appears at Least K Times/Solution.go @@ -0,0 +1,20 @@ +func countSubarrays(nums []int, k int) (ans int64) { + mx := slices.Max(nums) + n := len(nums) + cnt, j := 0, 0 + for _, x := range nums { + for ; j < n && cnt < k; j++ { + if nums[j] == mx { + cnt++ + } + } + if cnt < k { + break + } + ans += int64(n - j + 1) + if x == mx { + cnt-- + } + } + return +} \ No newline at end of file diff --git a/solution/2900-2999/2962.Count Subarrays Where Max Element Appears at Least K Times/Solution.java b/solution/2900-2999/2962.Count Subarrays Where Max Element Appears at Least K Times/Solution.java new file mode 100644 index 0000000000000..3be67ba5d5aa6 --- /dev/null +++ b/solution/2900-2999/2962.Count Subarrays Where Max Element Appears at Least K Times/Solution.java @@ -0,0 +1,19 @@ +class Solution { + public long countSubarrays(int[] nums, int k) { + int mx = Arrays.stream(nums).max().getAsInt(); + int n = nums.length; + long ans = 0; + int cnt = 0, j = 0; + for (int x : nums) { + while (j < n && cnt < k) { + cnt += nums[j++] == mx ? 1 : 0; + } + if (cnt < k) { + break; + } + ans += n - j + 1; + cnt -= x == mx ? 1 : 0; + } + return ans; + } +} \ No newline at end of file diff --git a/solution/2900-2999/2962.Count Subarrays Where Max Element Appears at Least K Times/Solution.py b/solution/2900-2999/2962.Count Subarrays Where Max Element Appears at Least K Times/Solution.py new file mode 100644 index 0000000000000..57295ad6d1f00 --- /dev/null +++ b/solution/2900-2999/2962.Count Subarrays Where Max Element Appears at Least K Times/Solution.py @@ -0,0 +1,14 @@ +class Solution: + def countSubarrays(self, nums: List[int], k: int) -> int: + mx = max(nums) + n = len(nums) + ans = cnt = j = 0 + for x in nums: + while j < n and cnt < k: + cnt += nums[j] == mx + j += 1 + if cnt < k: + break + ans += n - j + 1 + cnt -= x == mx + return ans diff --git a/solution/2900-2999/2962.Count Subarrays Where Max Element Appears at Least K Times/Solution.ts b/solution/2900-2999/2962.Count Subarrays Where Max Element Appears at Least K Times/Solution.ts new file mode 100644 index 0000000000000..0a02231e7d2b8 --- /dev/null +++ b/solution/2900-2999/2962.Count Subarrays Where Max Element Appears at Least K Times/Solution.ts @@ -0,0 +1,17 @@ +function countSubarrays(nums: number[], k: number): number { + const mx = Math.max(...nums); + const n = nums.length; + let [cnt, j] = [0, 0]; + let ans = 0; + for (const x of nums) { + for (; j < n && cnt < k; ++j) { + cnt += nums[j] === mx ? 1 : 0; + } + if (cnt < k) { + break; + } + ans += n - j + 1; + cnt -= x === mx ? 1 : 0; + } + return ans; +} diff --git a/solution/2900-2999/2963.Count the Number of Good Partitions/README.md b/solution/2900-2999/2963.Count the Number of Good Partitions/README.md index 7cd9db7aa01c5..8191aa78bd181 100644 --- a/solution/2900-2999/2963.Count the Number of Good Partitions/README.md +++ b/solution/2900-2999/2963.Count the Number of Good Partitions/README.md @@ -53,6 +53,18 @@ +**方法一:哈希表 + 分组 + 快速幂** + +根据题目描述,我们可以知道,相同的数字必须在同一个子数组中。因此,我们用一个哈希表 $last$ 记录每个数字最后一次出现的下标。 + +接下来,我们用一个下标 $j$ 标识已经出现过的元素中最后一个元素的下标,用一个变量 $k$ 记录当前可以划分的子数组的个数。 + +然后,我们从左到右遍历数组 $nums$,对于当前遍历到的数字 $nums[i]$,我们获取其最后一次出现的下标,更新 $j = \max(j, last[nums[i]])$。如果 $i = j$,那么说明当前位置可以是一个子数组的结尾,我们将 $k$ 增加 $1$。继续遍历,直到遍历完整个数组。 + +最后,我们考虑 $k$ 个子数组的划分方案数。子数组数量为 $k$,有 $k-1$ 个位置可以划分(拼接),因此方案数为 $2^{k-1}$。由于答案可能很大,我们需要对 $10^9 + 7$ 取模。这里我们可以使用快速幂来加速运算。 + +时间复杂度 $O(n)$,空间复杂度 $O(n)$。其中 $n$ 为数组 $nums$ 的长度。 + ### **Python3** @@ -60,7 +72,15 @@ ```python - +class Solution: + def numberOfGoodPartitions(self, nums: List[int]) -> int: + last = {x: i for i, x in enumerate(nums)} + mod = 10**9 + 7 + j, k = -1, 0 + for i, x in enumerate(nums): + j = max(j, last[x]) + k += i == j + return pow(2, k - 1, mod) ``` ### **Java** @@ -68,19 +88,127 @@ ```java - +class Solution { + public int numberOfGoodPartitions(int[] nums) { + Map last = new HashMap<>(); + int n = nums.length; + for (int i = 0; i < n; ++i) { + last.put(nums[i], i); + } + final int mod = (int) 1e9 + 7; + int j = -1; + int k = 0; + for (int i = 0; i < n; ++i) { + j = Math.max(j, last.get(nums[i])); + k += i == j ? 1 : 0; + } + return qpow(2, k - 1, mod); + } + + private int qpow(long a, int n, int mod) { + long ans = 1; + for (; n > 0; n >>= 1) { + if ((n & 1) == 1) { + ans = ans * a % mod; + } + a = a * a % mod; + } + return (int) ans; + } +} ``` ### **C++** ```cpp - +class Solution { +public: + int numberOfGoodPartitions(vector& nums) { + unordered_map last; + int n = nums.size(); + for (int i = 0; i < n; ++i) { + last[nums[i]] = i; + } + const int mod = 1e9 + 7; + int j = -1, k = 0; + for (int i = 0; i < n; ++i) { + j = max(j, last[nums[i]]); + k += i == j; + } + auto qpow = [&](long long a, int n, int mod) { + long long ans = 1; + for (; n; n >>= 1) { + if (n & 1) { + ans = ans * a % mod; + } + a = a * a % mod; + } + return (int) ans; + }; + return qpow(2, k - 1, mod); + } +}; ``` ### **Go** ```go +func numberOfGoodPartitions(nums []int) int { + qpow := func(a, n, mod int) int { + ans := 1 + for ; n > 0; n >>= 1 { + if n&1 == 1 { + ans = ans * a % mod + } + a = a * a % mod + } + return ans + } + last := map[int]int{} + for i, x := range nums { + last[x] = i + } + const mod int = 1e9 + 7 + j, k := -1, 0 + for i, x := range nums { + j = max(j, last[x]) + if i == j { + k++ + } + } + return qpow(2, k-1, mod) +} +``` +### **TypeScript** + +```ts +function numberOfGoodPartitions(nums: number[]): number { + const qpow = (a: number, n: number, mod: number) => { + let ans = 1; + for (; n; n >>= 1) { + if (n & 1) { + ans = Number((BigInt(ans) * BigInt(a)) % BigInt(mod)); + } + a = Number((BigInt(a) * BigInt(a)) % BigInt(mod)); + } + return ans; + }; + const last: Map = new Map(); + const n = nums.length; + for (let i = 0; i < n; ++i) { + last.set(nums[i], i); + } + const mod = 1e9 + 7; + let [j, k] = [-1, 0]; + for (let i = 0; i < n; ++i) { + j = Math.max(j, last.get(nums[i])!); + if (i === j) { + ++k; + } + } + return qpow(2, k - 1, mod); +} ``` ### **...** diff --git a/solution/2900-2999/2963.Count the Number of Good Partitions/README_EN.md b/solution/2900-2999/2963.Count the Number of Good Partitions/README_EN.md index 18d0489c8f52e..dbad178b95888 100644 --- a/solution/2900-2999/2963.Count the Number of Good Partitions/README_EN.md +++ b/solution/2900-2999/2963.Count the Number of Good Partitions/README_EN.md @@ -47,30 +47,158 @@ ## Solutions +**Solution 1: Hash Table + Grouping + Fast Power** + +According to the problem description, we know that the same number must be in the same subarray. Therefore, we use a hash table $last$ to record the index of the last occurrence of each number. + +Next, we use an index $j$ to mark the index of the last element that has appeared among the elements, and use a variable $k$ to record the number of subarrays that can currently be divided. + +Then, we traverse the array $nums$ from left to right. For the current number $nums[i]$ we are traversing, we get its last occurrence index and update $j = \max(j, last[nums[i]])$. If $i = j$, it means that the current position can be the end of a subarray, and we increase $k$ by $1$. Continue to traverse until the entire array is traversed. + +Finally, we consider the number of division schemes for $k$ subarrays. The number of subarrays is $k$, and there are $k-1$ positions that can be divided (concatenated), so the number of schemes is $2^{k-1}$. Since the answer may be very large, we need to take the modulo of $10^9 + 7$. Here we can use fast power to speed up the calculation. + +The time complexity is $O(n)$, and the space complexity is $O(n)$. Here, $n$ is the length of the array $nums$. + ### **Python3** ```python - +class Solution: + def numberOfGoodPartitions(self, nums: List[int]) -> int: + last = {x: i for i, x in enumerate(nums)} + mod = 10**9 + 7 + j, k = -1, 0 + for i, x in enumerate(nums): + j = max(j, last[x]) + k += i == j + return pow(2, k - 1, mod) ``` ### **Java** ```java - +class Solution { + public int numberOfGoodPartitions(int[] nums) { + Map last = new HashMap<>(); + int n = nums.length; + for (int i = 0; i < n; ++i) { + last.put(nums[i], i); + } + final int mod = (int) 1e9 + 7; + int j = -1; + int k = 0; + for (int i = 0; i < n; ++i) { + j = Math.max(j, last.get(nums[i])); + k += i == j ? 1 : 0; + } + return qpow(2, k - 1, mod); + } + + private int qpow(long a, int n, int mod) { + long ans = 1; + for (; n > 0; n >>= 1) { + if ((n & 1) == 1) { + ans = ans * a % mod; + } + a = a * a % mod; + } + return (int) ans; + } +} ``` ### **C++** ```cpp - +class Solution { +public: + int numberOfGoodPartitions(vector& nums) { + unordered_map last; + int n = nums.size(); + for (int i = 0; i < n; ++i) { + last[nums[i]] = i; + } + const int mod = 1e9 + 7; + int j = -1, k = 0; + for (int i = 0; i < n; ++i) { + j = max(j, last[nums[i]]); + k += i == j; + } + auto qpow = [&](long long a, int n, int mod) { + long long ans = 1; + for (; n; n >>= 1) { + if (n & 1) { + ans = ans * a % mod; + } + a = a * a % mod; + } + return (int) ans; + }; + return qpow(2, k - 1, mod); + } +}; ``` ### **Go** ```go +func numberOfGoodPartitions(nums []int) int { + qpow := func(a, n, mod int) int { + ans := 1 + for ; n > 0; n >>= 1 { + if n&1 == 1 { + ans = ans * a % mod + } + a = a * a % mod + } + return ans + } + last := map[int]int{} + for i, x := range nums { + last[x] = i + } + const mod int = 1e9 + 7 + j, k := -1, 0 + for i, x := range nums { + j = max(j, last[x]) + if i == j { + k++ + } + } + return qpow(2, k-1, mod) +} +``` +### **TypeScript** + +```ts +function numberOfGoodPartitions(nums: number[]): number { + const qpow = (a: number, n: number, mod: number) => { + let ans = 1; + for (; n; n >>= 1) { + if (n & 1) { + ans = Number((BigInt(ans) * BigInt(a)) % BigInt(mod)); + } + a = Number((BigInt(a) * BigInt(a)) % BigInt(mod)); + } + return ans; + }; + const last: Map = new Map(); + const n = nums.length; + for (let i = 0; i < n; ++i) { + last.set(nums[i], i); + } + const mod = 1e9 + 7; + let [j, k] = [-1, 0]; + for (let i = 0; i < n; ++i) { + j = Math.max(j, last.get(nums[i])!); + if (i === j) { + ++k; + } + } + return qpow(2, k - 1, mod); +} ``` ### **...** diff --git a/solution/2900-2999/2963.Count the Number of Good Partitions/Solution.cpp b/solution/2900-2999/2963.Count the Number of Good Partitions/Solution.cpp new file mode 100644 index 0000000000000..01d8b6dc11c2a --- /dev/null +++ b/solution/2900-2999/2963.Count the Number of Good Partitions/Solution.cpp @@ -0,0 +1,27 @@ +class Solution { +public: + int numberOfGoodPartitions(vector& nums) { + unordered_map last; + int n = nums.size(); + for (int i = 0; i < n; ++i) { + last[nums[i]] = i; + } + const int mod = 1e9 + 7; + int j = -1, k = 0; + for (int i = 0; i < n; ++i) { + j = max(j, last[nums[i]]); + k += i == j; + } + auto qpow = [&](long long a, int n, int mod) { + long long ans = 1; + for (; n; n >>= 1) { + if (n & 1) { + ans = ans * a % mod; + } + a = a * a % mod; + } + return (int) ans; + }; + return qpow(2, k - 1, mod); + } +}; \ No newline at end of file diff --git a/solution/2900-2999/2963.Count the Number of Good Partitions/Solution.go b/solution/2900-2999/2963.Count the Number of Good Partitions/Solution.go new file mode 100644 index 0000000000000..f732ff7dd37dc --- /dev/null +++ b/solution/2900-2999/2963.Count the Number of Good Partitions/Solution.go @@ -0,0 +1,25 @@ +func numberOfGoodPartitions(nums []int) int { + qpow := func(a, n, mod int) int { + ans := 1 + for ; n > 0; n >>= 1 { + if n&1 == 1 { + ans = ans * a % mod + } + a = a * a % mod + } + return ans + } + last := map[int]int{} + for i, x := range nums { + last[x] = i + } + const mod int = 1e9 + 7 + j, k := -1, 0 + for i, x := range nums { + j = max(j, last[x]) + if i == j { + k++ + } + } + return qpow(2, k-1, mod) +} \ No newline at end of file diff --git a/solution/2900-2999/2963.Count the Number of Good Partitions/Solution.java b/solution/2900-2999/2963.Count the Number of Good Partitions/Solution.java new file mode 100644 index 0000000000000..176acc9a58dda --- /dev/null +++ b/solution/2900-2999/2963.Count the Number of Good Partitions/Solution.java @@ -0,0 +1,28 @@ +class Solution { + public int numberOfGoodPartitions(int[] nums) { + Map last = new HashMap<>(); + int n = nums.length; + for (int i = 0; i < n; ++i) { + last.put(nums[i], i); + } + final int mod = (int) 1e9 + 7; + int j = -1; + int k = 0; + for (int i = 0; i < n; ++i) { + j = Math.max(j, last.get(nums[i])); + k += i == j ? 1 : 0; + } + return qpow(2, k - 1, mod); + } + + private int qpow(long a, int n, int mod) { + long ans = 1; + for (; n > 0; n >>= 1) { + if ((n & 1) == 1) { + ans = ans * a % mod; + } + a = a * a % mod; + } + return (int) ans; + } +} \ No newline at end of file diff --git a/solution/2900-2999/2963.Count the Number of Good Partitions/Solution.py b/solution/2900-2999/2963.Count the Number of Good Partitions/Solution.py new file mode 100644 index 0000000000000..f4ec00970e7c3 --- /dev/null +++ b/solution/2900-2999/2963.Count the Number of Good Partitions/Solution.py @@ -0,0 +1,9 @@ +class Solution: + def numberOfGoodPartitions(self, nums: List[int]) -> int: + last = {x: i for i, x in enumerate(nums)} + mod = 10**9 + 7 + j, k = -1, 0 + for i, x in enumerate(nums): + j = max(j, last[x]) + k += i == j + return pow(2, k - 1, mod) diff --git a/solution/2900-2999/2963.Count the Number of Good Partitions/Solution.ts b/solution/2900-2999/2963.Count the Number of Good Partitions/Solution.ts new file mode 100644 index 0000000000000..fc28975c55200 --- /dev/null +++ b/solution/2900-2999/2963.Count the Number of Good Partitions/Solution.ts @@ -0,0 +1,26 @@ +function numberOfGoodPartitions(nums: number[]): number { + const qpow = (a: number, n: number, mod: number) => { + let ans = 1; + for (; n; n >>= 1) { + if (n & 1) { + ans = Number((BigInt(ans) * BigInt(a)) % BigInt(mod)); + } + a = Number((BigInt(a) * BigInt(a)) % BigInt(mod)); + } + return ans; + }; + const last: Map = new Map(); + const n = nums.length; + for (let i = 0; i < n; ++i) { + last.set(nums[i], i); + } + const mod = 1e9 + 7; + let [j, k] = [-1, 0]; + for (let i = 0; i < n; ++i) { + j = Math.max(j, last.get(nums[i])!); + if (i === j) { + ++k; + } + } + return qpow(2, k - 1, mod); +} diff --git a/solution/config.py b/solution/config.py index aa86e05780677..e68738a785653 100644 --- a/solution/config.py +++ b/solution/config.py @@ -56,4 +56,5 @@ 2606, 2731, 2788, + 2960, ] From 12cf12a7e8d8ce7c99f21786c6882a3da215e8cf Mon Sep 17 00:00:00 2001 From: Libin YANG Date: Mon, 11 Dec 2023 19:36:47 +0800 Subject: [PATCH 4/5] feat: add solutions to lc problem: No.2697 (#2084) No.2697.Lexicographically Smallest Palindrome --- .../README.md | 54 +++++------------ .../README_EN.md | 58 +++++++------------ .../Solution.cpp | 18 +++--- .../Solution.go | 9 +-- .../Solution.java | 18 +++--- .../Solution.py | 17 +++--- .../Solution.rs | 24 +++----- .../Solution.ts | 4 +- .../README_EN.md | 6 ++ 9 files changed, 77 insertions(+), 131 deletions(-) diff --git a/solution/2600-2699/2697.Lexicographically Smallest Palindrome/README.md b/solution/2600-2699/2697.Lexicographically Smallest Palindrome/README.md index f03dcd4cb5c27..5eda0088bf66a 100644 --- a/solution/2600-2699/2697.Lexicographically Smallest Palindrome/README.md +++ b/solution/2600-2699/2697.Lexicographically Smallest Palindrome/README.md @@ -54,7 +54,7 @@ **方法一:贪心 + 双指针** -我们用两个指针 $i$ 和 $j$ 分别指向字符串的首尾,初始时 $i=0,j=n-1$,其中 $n$ 是字符串的长度。每次比较 $s[i]$ 和 $s[j]$,如果二者不相同,则将其中较大的字符修改为较小的字符,使得两者相同。这样在修改之后,原字符串 $s$ 就变成了一个回文串。 +我们用两个指针 $i$ 和 $j$ 分别指向字符串的首尾,初始时 $i = 0$, $j = n - 1$。每一次,我们将 $s[i]$ 和 $s[j]$ 都修改为其中较小的那个字符,使得它们相等。修改之后,原字符串 $s$ 变成了一个回文串。 时间复杂度 $O(n)$,其中 $n$ 是字符串的长度。我们只需要遍历一遍字符串即可。忽略答案的空间消耗,空间复杂度 $O(1)$。 @@ -67,11 +67,10 @@ ```python class Solution: def makeSmallestPalindrome(self, s: str) -> str: - i, j = 0, len(s) - 1 cs = list(s) + i, j = 0, len(s) - 1 while i < j: - if s[i] != s[j]: - cs[i] = cs[j] = min(s[i], s[j]) + cs[i] = cs[j] = min(cs[i], cs[j]) i, j = i + 1, j - 1 return "".join(cs) ``` @@ -85,11 +84,9 @@ class Solution { public String makeSmallestPalindrome(String s) { char[] cs = s.toCharArray(); for (int i = 0, j = cs.length - 1; i < j; ++i, --j) { - if (cs[i] != cs[j]) { - cs[i] = cs[j] = cs[i] < cs[j] ? cs[i] : cs[j]; - } + cs[i] = cs[j] = (char) Math.min(cs[i], cs[j]); } - return String.valueOf(cs); + return new String(cs); } } ``` @@ -101,9 +98,7 @@ class Solution { public: string makeSmallestPalindrome(string s) { for (int i = 0, j = s.size() - 1; i < j; ++i, --j) { - if (s[i] != s[j]) { - s[i] = s[j] = s[i] < s[j] ? s[i] : s[j]; - } + s[i] = s[j] = min(s[i], s[j]); } return s; } @@ -116,13 +111,8 @@ public: func makeSmallestPalindrome(s string) string { cs := []byte(s) for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 { - if cs[i] != cs[j] { - if cs[i] < cs[j] { - cs[j] = cs[i] - } else { - cs[i] = cs[j] - } - } + cs[i] = min(cs[i], cs[j]) + cs[j] = cs[i] } return string(cs) } @@ -134,9 +124,7 @@ func makeSmallestPalindrome(s string) string { function makeSmallestPalindrome(s: string): string { const cs = s.split(''); for (let i = 0, j = s.length - 1; i < j; ++i, --j) { - if (s[i] !== s[j]) { - cs[i] = cs[j] = s[i] < s[j] ? s[i] : s[j]; - } + cs[i] = cs[j] = String.fromCharCode(Math.min(cs[i].charCodeAt(0), cs[j].charCodeAt(0))); } return cs.join(''); } @@ -147,24 +135,14 @@ function makeSmallestPalindrome(s: string): string { ```rust impl Solution { pub fn make_smallest_palindrome(s: String) -> String { - let mut b: Vec = s.bytes().collect(); - let mut i = 0; - let mut j = b.len() - 1; - - while i < j { - if b[i] != b[j] { - if b[i] < b[j] { - b[j] = b[i]; - } else { - b[i] = b[j]; - } - } - - i += 1; - j -= 1; + let mut cs: Vec = s.chars().collect(); + let n = cs.len(); + for i in 0..n / 2 { + let j = n - 1 - i; + cs[i] = std::cmp::min(cs[i], cs[j]); + cs[j] = cs[i]; } - - String::from_utf8(b).unwrap() + cs.into_iter().collect() } } ``` diff --git a/solution/2600-2699/2697.Lexicographically Smallest Palindrome/README_EN.md b/solution/2600-2699/2697.Lexicographically Smallest Palindrome/README_EN.md index ee3ab208df99a..85ec129d7aa88 100644 --- a/solution/2600-2699/2697.Lexicographically Smallest Palindrome/README_EN.md +++ b/solution/2600-2699/2697.Lexicographically Smallest Palindrome/README_EN.md @@ -47,6 +47,12 @@ ## Solutions +**Solution 1: Greedy + Two Pointers** + +We use two pointers $i$ and $j$ to point to the beginning and end of the string, initially $i=0,j=n-1$, where $n$ is the length of the string. Each time we compare $s[i]$ and $s[j]$, if they are not the same, we modify the larger character to the smaller one to make them the same. After the modification, the original string $s$ becomes a palindrome. + +The time complexity is $O(n)$, where $n$ is the length of the string. We only need to traverse the string once. Ignoring the space consumption of the answer, the space complexity is $O(1)$. + ### **Python3** @@ -54,11 +60,10 @@ ```python class Solution: def makeSmallestPalindrome(self, s: str) -> str: - i, j = 0, len(s) - 1 cs = list(s) + i, j = 0, len(s) - 1 while i < j: - if s[i] != s[j]: - cs[i] = cs[j] = min(s[i], s[j]) + cs[i] = cs[j] = min(cs[i], cs[j]) i, j = i + 1, j - 1 return "".join(cs) ``` @@ -70,11 +75,9 @@ class Solution { public String makeSmallestPalindrome(String s) { char[] cs = s.toCharArray(); for (int i = 0, j = cs.length - 1; i < j; ++i, --j) { - if (cs[i] != cs[j]) { - cs[i] = cs[j] = cs[i] < cs[j] ? cs[i] : cs[j]; - } + cs[i] = cs[j] = (char) Math.min(cs[i], cs[j]); } - return String.valueOf(cs); + return new String(cs); } } ``` @@ -86,9 +89,7 @@ class Solution { public: string makeSmallestPalindrome(string s) { for (int i = 0, j = s.size() - 1; i < j; ++i, --j) { - if (s[i] != s[j]) { - s[i] = s[j] = s[i] < s[j] ? s[i] : s[j]; - } + s[i] = s[j] = min(s[i], s[j]); } return s; } @@ -101,13 +102,8 @@ public: func makeSmallestPalindrome(s string) string { cs := []byte(s) for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 { - if cs[i] != cs[j] { - if cs[i] < cs[j] { - cs[j] = cs[i] - } else { - cs[i] = cs[j] - } - } + cs[i] = min(cs[i], cs[j]) + cs[j] = cs[i] } return string(cs) } @@ -119,9 +115,7 @@ func makeSmallestPalindrome(s string) string { function makeSmallestPalindrome(s: string): string { const cs = s.split(''); for (let i = 0, j = s.length - 1; i < j; ++i, --j) { - if (s[i] !== s[j]) { - cs[i] = cs[j] = s[i] < s[j] ? s[i] : s[j]; - } + cs[i] = cs[j] = String.fromCharCode(Math.min(cs[i].charCodeAt(0), cs[j].charCodeAt(0))); } return cs.join(''); } @@ -132,24 +126,14 @@ function makeSmallestPalindrome(s: string): string { ```rust impl Solution { pub fn make_smallest_palindrome(s: String) -> String { - let mut b: Vec = s.bytes().collect(); - let mut i = 0; - let mut j = b.len() - 1; - - while i < j { - if b[i] != b[j] { - if b[i] < b[j] { - b[j] = b[i]; - } else { - b[i] = b[j]; - } - } - - i += 1; - j -= 1; + let mut cs: Vec = s.chars().collect(); + let n = cs.len(); + for i in 0..n / 2 { + let j = n - 1 - i; + cs[i] = std::cmp::min(cs[i], cs[j]); + cs[j] = cs[i]; } - - String::from_utf8(b).unwrap() + cs.into_iter().collect() } } ``` diff --git a/solution/2600-2699/2697.Lexicographically Smallest Palindrome/Solution.cpp b/solution/2600-2699/2697.Lexicographically Smallest Palindrome/Solution.cpp index b9e4c08676ae6..6d18d9f4c7795 100644 --- a/solution/2600-2699/2697.Lexicographically Smallest Palindrome/Solution.cpp +++ b/solution/2600-2699/2697.Lexicographically Smallest Palindrome/Solution.cpp @@ -1,11 +1,9 @@ -class Solution { -public: - string makeSmallestPalindrome(string s) { - for (int i = 0, j = s.size() - 1; i < j; ++i, --j) { - if (s[i] != s[j]) { - s[i] = s[j] = s[i] < s[j] ? s[i] : s[j]; - } - } - return s; - } +class Solution { +public: + string makeSmallestPalindrome(string s) { + for (int i = 0, j = s.size() - 1; i < j; ++i, --j) { + s[i] = s[j] = min(s[i], s[j]); + } + return s; + } }; \ No newline at end of file diff --git a/solution/2600-2699/2697.Lexicographically Smallest Palindrome/Solution.go b/solution/2600-2699/2697.Lexicographically Smallest Palindrome/Solution.go index 5b36cc6802faa..c38e58839d78a 100644 --- a/solution/2600-2699/2697.Lexicographically Smallest Palindrome/Solution.go +++ b/solution/2600-2699/2697.Lexicographically Smallest Palindrome/Solution.go @@ -1,13 +1,8 @@ func makeSmallestPalindrome(s string) string { cs := []byte(s) for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 { - if cs[i] != cs[j] { - if cs[i] < cs[j] { - cs[j] = cs[i] - } else { - cs[i] = cs[j] - } - } + cs[i] = min(cs[i], cs[j]) + cs[j] = cs[i] } return string(cs) } \ No newline at end of file diff --git a/solution/2600-2699/2697.Lexicographically Smallest Palindrome/Solution.java b/solution/2600-2699/2697.Lexicographically Smallest Palindrome/Solution.java index ad01278102f6a..0896d09f92443 100644 --- a/solution/2600-2699/2697.Lexicographically Smallest Palindrome/Solution.java +++ b/solution/2600-2699/2697.Lexicographically Smallest Palindrome/Solution.java @@ -1,11 +1,9 @@ -class Solution { - public String makeSmallestPalindrome(String s) { - char[] cs = s.toCharArray(); - for (int i = 0, j = cs.length - 1; i < j; ++i, --j) { - if (cs[i] != cs[j]) { - cs[i] = cs[j] = cs[i] < cs[j] ? cs[i] : cs[j]; - } - } - return String.valueOf(cs); - } +class Solution { + public String makeSmallestPalindrome(String s) { + char[] cs = s.toCharArray(); + for (int i = 0, j = cs.length - 1; i < j; ++i, --j) { + cs[i] = cs[j] = (char) Math.min(cs[i], cs[j]); + } + return new String(cs); + } } \ No newline at end of file diff --git a/solution/2600-2699/2697.Lexicographically Smallest Palindrome/Solution.py b/solution/2600-2699/2697.Lexicographically Smallest Palindrome/Solution.py index 073b517ffb7a9..b374713ad852b 100644 --- a/solution/2600-2699/2697.Lexicographically Smallest Palindrome/Solution.py +++ b/solution/2600-2699/2697.Lexicographically Smallest Palindrome/Solution.py @@ -1,9 +1,8 @@ -class Solution: - def makeSmallestPalindrome(self, s: str) -> str: - i, j = 0, len(s) - 1 - cs = list(s) - while i < j: - if s[i] != s[j]: - cs[i] = cs[j] = min(s[i], s[j]) - i, j = i + 1, j - 1 - return "".join(cs) +class Solution: + def makeSmallestPalindrome(self, s: str) -> str: + cs = list(s) + i, j = 0, len(s) - 1 + while i < j: + cs[i] = cs[j] = min(cs[i], cs[j]) + i, j = i + 1, j - 1 + return "".join(cs) diff --git a/solution/2600-2699/2697.Lexicographically Smallest Palindrome/Solution.rs b/solution/2600-2699/2697.Lexicographically Smallest Palindrome/Solution.rs index 6925d311c162b..2d8eec2abe900 100644 --- a/solution/2600-2699/2697.Lexicographically Smallest Palindrome/Solution.rs +++ b/solution/2600-2699/2697.Lexicographically Smallest Palindrome/Solution.rs @@ -1,22 +1,12 @@ impl Solution { pub fn make_smallest_palindrome(s: String) -> String { - let mut b: Vec = s.bytes().collect(); - let mut i = 0; - let mut j = b.len() - 1; - - while i < j { - if b[i] != b[j] { - if b[i] < b[j] { - b[j] = b[i]; - } else { - b[i] = b[j]; - } - } - - i += 1; - j -= 1; + let mut cs: Vec = s.chars().collect(); + let n = cs.len(); + for i in 0..n / 2 { + let j = n - 1 - i; + cs[i] = std::cmp::min(cs[i], cs[j]); + cs[j] = cs[i]; } - - String::from_utf8(b).unwrap() + cs.into_iter().collect() } } diff --git a/solution/2600-2699/2697.Lexicographically Smallest Palindrome/Solution.ts b/solution/2600-2699/2697.Lexicographically Smallest Palindrome/Solution.ts index 9b507864642ec..4d4f567aef53a 100644 --- a/solution/2600-2699/2697.Lexicographically Smallest Palindrome/Solution.ts +++ b/solution/2600-2699/2697.Lexicographically Smallest Palindrome/Solution.ts @@ -1,9 +1,7 @@ function makeSmallestPalindrome(s: string): string { const cs = s.split(''); for (let i = 0, j = s.length - 1; i < j; ++i, --j) { - if (s[i] !== s[j]) { - cs[i] = cs[j] = s[i] < s[j] ? s[i] : s[j]; - } + cs[i] = cs[j] = String.fromCharCode(Math.min(cs[i].charCodeAt(0), cs[j].charCodeAt(0))); } return cs.join(''); } diff --git a/solution/2700-2799/2702.Minimum Operations to Make Numbers Non-positive/README_EN.md b/solution/2700-2799/2702.Minimum Operations to Make Numbers Non-positive/README_EN.md index 619b355cb5499..37bef1e3edb99 100644 --- a/solution/2700-2799/2702.Minimum Operations to Make Numbers Non-positive/README_EN.md +++ b/solution/2700-2799/2702.Minimum Operations to Make Numbers Non-positive/README_EN.md @@ -45,6 +45,12 @@ Now, all the numbers in nums are non-positive. Therefore, we return 3. ## Solutions +**Solution 1: Binary Search** + +We notice that if an operation count $t$ can make all numbers less than or equal to $0$, then for any $t' > t$, the operation count $t'$ can also make all numbers less than or equal to $0$. Therefore, we can use binary search to find the minimum operation count. + +We define the left boundary of the binary search as $l=0$, and the right boundary as $r=\max(nums)$. Each time we perform a binary search, we find the middle value $mid=\lfloor\frac{l+r}{2}\rfloor$, and then determine whether there exists an operation method that does not exceed $mid$ and makes all numbers less than or equal to $0$. If it exists, we update the right boundary $r = mid$, otherwise, we update the left boundary + ### **Python3** From 211ebb3c60e702ce4141556c72f386eefeb050ca Mon Sep 17 00:00:00 2001 From: Libin YANG Date: Mon, 11 Dec 2023 20:37:37 +0800 Subject: [PATCH 5/5] feat: add solutions to lc problem: No.2415 (#2085) No.2415.Reverse Odd Levels of Binary Tree --- .../README.md | 103 ++++++----------- .../README_EN.md | 105 +++++++----------- .../Solution.cpp | 78 ++++++------- .../Solution.go | 17 +-- .../Solution.java | 85 +++++++------- .../Solution.py | 50 ++++----- .../Solution.ts | 27 ++--- .../README.md | 2 +- 8 files changed, 187 insertions(+), 280 deletions(-) diff --git a/solution/2400-2499/2415.Reverse Odd Levels of Binary Tree/README.md b/solution/2400-2499/2415.Reverse Odd Levels of Binary Tree/README.md index 619fe7539262c..03ac2cad85b51 100644 --- a/solution/2400-2499/2415.Reverse Odd Levels of Binary Tree/README.md +++ b/solution/2400-2499/2415.Reverse Odd Levels of Binary Tree/README.md @@ -65,9 +65,9 @@ **方法一:BFS** -BFS 遍历二叉树,遍历到奇数层时,反转该层节点的值。 +我们可以使用广度优先搜索的方法,用一个队列 $q$ 来存储每一层的节点,用一个变量 $i$ 记录当前层数。若 $i$ 为奇数,则将当前层的节点值反转。 -时间复杂度 $O(n)$,空间复杂度 $O(n)$。其中 $n$ 为二叉树的节点个数。 +时间复杂度 $O(n)$,空间复杂度 $O(n)$。其中 $n$ 是二叉树的节点数。 @@ -87,20 +87,16 @@ class Solution: q = deque([root]) i = 0 while q: - t = [] + if i & 1: + l, r = 0, len(q) - 1 + while l < r: + q[l].val, q[r].val = q[r].val, q[l].val + l, r = l + 1, r - 1 for _ in range(len(q)): node = q.popleft() - if i & 1: - t.append(node) if node.left: q.append(node.left) - if node.right: q.append(node.right) - if t: - j, k = 0, len(t) - 1 - while j < k: - t[j].val, t[k].val = t[k].val, t[j].val - j, k = j + 1, k - 1 i += 1 return root ``` @@ -129,30 +125,23 @@ class Solution { public TreeNode reverseOddLevels(TreeNode root) { Deque q = new ArrayDeque<>(); q.offer(root); - int i = 0; - while (!q.isEmpty()) { + for (int i = 0; !q.isEmpty(); ++i) { List t = new ArrayList<>(); - for (int n = q.size(); n > 0; --n) { - TreeNode node = q.pollFirst(); + for (int k = q.size(); k > 0; --k) { + var node = q.poll(); if (i % 2 == 1) { t.add(node); } if (node.left != null) { q.offer(node.left); - } - if (node.right != null) { q.offer(node.right); } } - if (!t.isEmpty()) { - int j = 0, k = t.size() - 1; - for (; j < k; ++j, --k) { - int v = t.get(j).val; - t.get(j).val = t.get(k).val; - t.get(k).val = v; - } + for (int l = 0, r = t.size() - 1; l < r; ++l, --r) { + var x = t.get(l).val; + t.get(l).val = t.get(r).val; + t.get(r).val = x; } - ++i; } return root; } @@ -177,11 +166,9 @@ class Solution { public: TreeNode* reverseOddLevels(TreeNode* root) { queue q{{root}}; - int i = 0; - vector t; - while (!q.empty()) { - t.clear(); - for (int n = q.size(); n; --n) { + for (int i = 0; q.size(); ++i) { + vector t; + for (int k = q.size(); k; --k) { TreeNode* node = q.front(); q.pop(); if (i & 1) { @@ -189,20 +176,12 @@ public: } if (node->left) { q.push(node->left); - } - if (node->right) { q.push(node->right); } } - if (t.size()) { - int j = 0, k = t.size() - 1; - for (; j < k; ++j, --k) { - int v = t[j]->val; - t[j]->val = t[k]->val; - t[k]->val = v; - } + for (int l = 0, r = t.size() - 1; l < r; ++l, --r) { + swap(t[l]->val, t[r]->val); } - ++i; } return root; } @@ -222,10 +201,9 @@ public: */ func reverseOddLevels(root *TreeNode) *TreeNode { q := []*TreeNode{root} - i := 0 - for len(q) > 0 { + for i := 0; len(q) > 0; i++ { t := []*TreeNode{} - for n := len(q); n > 0; n-- { + for k := len(q); k > 0; k-- { node := q[0] q = q[1:] if i%2 == 1 { @@ -233,20 +211,12 @@ func reverseOddLevels(root *TreeNode) *TreeNode { } if node.Left != nil { q = append(q, node.Left) - } - if node.Right != nil { q = append(q, node.Right) } } - if len(t) > 0 { - j, k := 0, len(t)-1 - for ; j < k; j, k = j+1, k-1 { - v := t[j].Val - t[j].Val = t[k].Val - t[k].Val = v - } + for l, r := 0, len(t)-1; l < r; l, r = l+1, r-1 { + t[l].Val, t[r].Val = t[r].Val, t[l].Val } - i++ } return root } @@ -270,24 +240,21 @@ func reverseOddLevels(root *TreeNode) *TreeNode { */ function reverseOddLevels(root: TreeNode | null): TreeNode | null { - const queue = [root]; - let d = 0; - while (queue.length !== 0) { - const n = queue.length; - const t: TreeNode[] = []; - for (let i = 0; i < n; i++) { - const node = queue.shift(); - if (d % 2 == 1) { - t.push(node); + const q: TreeNode[] = [root]; + for (let i = 0; q.length > 0; ++i) { + if (i % 2) { + for (let l = 0, r = q.length - 1; l < r; ++l, --r) { + [q[l].val, q[r].val] = [q[r].val, q[l].val]; } - node.left && queue.push(node.left); - node.right && queue.push(node.right); } - const m = t.length; - for (let i = 0; i < m >> 1; i++) { - [t[i].val, t[m - 1 - i].val] = [t[m - 1 - i].val, t[i].val]; + const nq: TreeNode[] = []; + for (const { left, right } of q) { + if (left) { + nq.push(left); + nq.push(right); + } } - d++; + q.splice(0, q.length, ...nq); } return root; } diff --git a/solution/2400-2499/2415.Reverse Odd Levels of Binary Tree/README_EN.md b/solution/2400-2499/2415.Reverse Odd Levels of Binary Tree/README_EN.md index efd3e38fba4c3..269633d357be4 100644 --- a/solution/2400-2499/2415.Reverse Odd Levels of Binary Tree/README_EN.md +++ b/solution/2400-2499/2415.Reverse Odd Levels of Binary Tree/README_EN.md @@ -58,6 +58,12 @@ The nodes at level 3 were 1, 1, 1, 1, 2, 2, 2, 2, and are 2, 2, 2, 2, 1, 1, 1, 1 ## Solutions +**Solution 1: BFS** + +We can use the Breadth-First Search (BFS) method, using a queue $q$ to store the nodes of each level, and a variable $i$ to record the current level. If $i$ is odd, we reverse the values of the nodes at the current level. + +The time complexity is $O(n)$, and the space complexity is $O(n)$. Here, $n$ is the number of nodes in the binary tree. + ### **Python3** @@ -74,20 +80,16 @@ class Solution: q = deque([root]) i = 0 while q: - t = [] + if i & 1: + l, r = 0, len(q) - 1 + while l < r: + q[l].val, q[r].val = q[r].val, q[l].val + l, r = l + 1, r - 1 for _ in range(len(q)): node = q.popleft() - if i & 1: - t.append(node) if node.left: q.append(node.left) - if node.right: q.append(node.right) - if t: - j, k = 0, len(t) - 1 - while j < k: - t[j].val, t[k].val = t[k].val, t[j].val - j, k = j + 1, k - 1 i += 1 return root ``` @@ -114,30 +116,23 @@ class Solution { public TreeNode reverseOddLevels(TreeNode root) { Deque q = new ArrayDeque<>(); q.offer(root); - int i = 0; - while (!q.isEmpty()) { + for (int i = 0; !q.isEmpty(); ++i) { List t = new ArrayList<>(); - for (int n = q.size(); n > 0; --n) { - TreeNode node = q.pollFirst(); + for (int k = q.size(); k > 0; --k) { + var node = q.poll(); if (i % 2 == 1) { t.add(node); } if (node.left != null) { q.offer(node.left); - } - if (node.right != null) { q.offer(node.right); } } - if (!t.isEmpty()) { - int j = 0, k = t.size() - 1; - for (; j < k; ++j, --k) { - int v = t.get(j).val; - t.get(j).val = t.get(k).val; - t.get(k).val = v; - } + for (int l = 0, r = t.size() - 1; l < r; ++l, --r) { + var x = t.get(l).val; + t.get(l).val = t.get(r).val; + t.get(r).val = x; } - ++i; } return root; } @@ -162,11 +157,9 @@ class Solution { public: TreeNode* reverseOddLevels(TreeNode* root) { queue q{{root}}; - int i = 0; - vector t; - while (!q.empty()) { - t.clear(); - for (int n = q.size(); n; --n) { + for (int i = 0; q.size(); ++i) { + vector t; + for (int k = q.size(); k; --k) { TreeNode* node = q.front(); q.pop(); if (i & 1) { @@ -174,20 +167,12 @@ public: } if (node->left) { q.push(node->left); - } - if (node->right) { q.push(node->right); } } - if (t.size()) { - int j = 0, k = t.size() - 1; - for (; j < k; ++j, --k) { - int v = t[j]->val; - t[j]->val = t[k]->val; - t[k]->val = v; - } + for (int l = 0, r = t.size() - 1; l < r; ++l, --r) { + swap(t[l]->val, t[r]->val); } - ++i; } return root; } @@ -207,10 +192,9 @@ public: */ func reverseOddLevels(root *TreeNode) *TreeNode { q := []*TreeNode{root} - i := 0 - for len(q) > 0 { + for i := 0; len(q) > 0; i++ { t := []*TreeNode{} - for n := len(q); n > 0; n-- { + for k := len(q); k > 0; k-- { node := q[0] q = q[1:] if i%2 == 1 { @@ -218,20 +202,12 @@ func reverseOddLevels(root *TreeNode) *TreeNode { } if node.Left != nil { q = append(q, node.Left) - } - if node.Right != nil { q = append(q, node.Right) } } - if len(t) > 0 { - j, k := 0, len(t)-1 - for ; j < k; j, k = j+1, k-1 { - v := t[j].Val - t[j].Val = t[k].Val - t[k].Val = v - } + for l, r := 0, len(t)-1; l < r; l, r = l+1, r-1 { + t[l].Val, t[r].Val = t[r].Val, t[l].Val } - i++ } return root } @@ -255,24 +231,21 @@ func reverseOddLevels(root *TreeNode) *TreeNode { */ function reverseOddLevels(root: TreeNode | null): TreeNode | null { - const queue = [root]; - let d = 0; - while (queue.length !== 0) { - const n = queue.length; - const t: TreeNode[] = []; - for (let i = 0; i < n; i++) { - const node = queue.shift(); - if (d % 2 == 1) { - t.push(node); + const q: TreeNode[] = [root]; + for (let i = 0; q.length > 0; ++i) { + if (i % 2) { + for (let l = 0, r = q.length - 1; l < r; ++l, --r) { + [q[l].val, q[r].val] = [q[r].val, q[l].val]; } - node.left && queue.push(node.left); - node.right && queue.push(node.right); } - const m = t.length; - for (let i = 0; i < m >> 1; i++) { - [t[i].val, t[m - 1 - i].val] = [t[m - 1 - i].val, t[i].val]; + const nq: TreeNode[] = []; + for (const { left, right } of q) { + if (left) { + nq.push(left); + nq.push(right); + } } - d++; + q.splice(0, q.length, ...nq); } return root; } diff --git a/solution/2400-2499/2415.Reverse Odd Levels of Binary Tree/Solution.cpp b/solution/2400-2499/2415.Reverse Odd Levels of Binary Tree/Solution.cpp index 2822130ad73af..1aba662067d62 100644 --- a/solution/2400-2499/2415.Reverse Odd Levels of Binary Tree/Solution.cpp +++ b/solution/2400-2499/2415.Reverse Odd Levels of Binary Tree/Solution.cpp @@ -1,45 +1,35 @@ -/** - * Definition for a binary tree node. - * struct TreeNode { - * int val; - * TreeNode *left; - * TreeNode *right; - * TreeNode() : val(0), left(nullptr), right(nullptr) {} - * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} - * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} - * }; - */ -class Solution { -public: - TreeNode* reverseOddLevels(TreeNode* root) { - queue q{{root}}; - int i = 0; - vector t; - while (!q.empty()) { - t.clear(); - for (int n = q.size(); n; --n) { - TreeNode* node = q.front(); - q.pop(); - if (i & 1) { - t.push_back(node); - } - if (node->left) { - q.push(node->left); - } - if (node->right) { - q.push(node->right); - } - } - if (t.size()) { - int j = 0, k = t.size() - 1; - for (; j < k; ++j, --k) { - int v = t[j]->val; - t[j]->val = t[k]->val; - t[k]->val = v; - } - } - ++i; - } - return root; - } +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + TreeNode* reverseOddLevels(TreeNode* root) { + queue q{{root}}; + for (int i = 0; q.size(); ++i) { + vector t; + for (int k = q.size(); k; --k) { + TreeNode* node = q.front(); + q.pop(); + if (i & 1) { + t.push_back(node); + } + if (node->left) { + q.push(node->left); + q.push(node->right); + } + } + for (int l = 0, r = t.size() - 1; l < r; ++l, --r) { + swap(t[l]->val, t[r]->val); + } + } + return root; + } }; \ No newline at end of file diff --git a/solution/2400-2499/2415.Reverse Odd Levels of Binary Tree/Solution.go b/solution/2400-2499/2415.Reverse Odd Levels of Binary Tree/Solution.go index 95a1e1439f231..c64148f85f4b8 100644 --- a/solution/2400-2499/2415.Reverse Odd Levels of Binary Tree/Solution.go +++ b/solution/2400-2499/2415.Reverse Odd Levels of Binary Tree/Solution.go @@ -8,10 +8,9 @@ */ func reverseOddLevels(root *TreeNode) *TreeNode { q := []*TreeNode{root} - i := 0 - for len(q) > 0 { + for i := 0; len(q) > 0; i++ { t := []*TreeNode{} - for n := len(q); n > 0; n-- { + for k := len(q); k > 0; k-- { node := q[0] q = q[1:] if i%2 == 1 { @@ -19,20 +18,12 @@ func reverseOddLevels(root *TreeNode) *TreeNode { } if node.Left != nil { q = append(q, node.Left) - } - if node.Right != nil { q = append(q, node.Right) } } - if len(t) > 0 { - j, k := 0, len(t)-1 - for ; j < k; j, k = j+1, k-1 { - v := t[j].Val - t[j].Val = t[k].Val - t[k].Val = v - } + for l, r := 0, len(t)-1; l < r; l, r = l+1, r-1 { + t[l].Val, t[r].Val = t[r].Val, t[l].Val } - i++ } return root } \ No newline at end of file diff --git a/solution/2400-2499/2415.Reverse Odd Levels of Binary Tree/Solution.java b/solution/2400-2499/2415.Reverse Odd Levels of Binary Tree/Solution.java index 5d9ab34b54422..3be6bc67f81b7 100644 --- a/solution/2400-2499/2415.Reverse Odd Levels of Binary Tree/Solution.java +++ b/solution/2400-2499/2415.Reverse Odd Levels of Binary Tree/Solution.java @@ -1,47 +1,40 @@ -/** - * Definition for a binary tree node. - * public class TreeNode { - * int val; - * TreeNode left; - * TreeNode right; - * TreeNode() {} - * TreeNode(int val) { this.val = val; } - * TreeNode(int val, TreeNode left, TreeNode right) { - * this.val = val; - * this.left = left; - * this.right = right; - * } - * } - */ -class Solution { - public TreeNode reverseOddLevels(TreeNode root) { - Deque q = new ArrayDeque<>(); - q.offer(root); - int i = 0; - while (!q.isEmpty()) { - List t = new ArrayList<>(); - for (int n = q.size(); n > 0; --n) { - TreeNode node = q.pollFirst(); - if (i % 2 == 1) { - t.add(node); - } - if (node.left != null) { - q.offer(node.left); - } - if (node.right != null) { - q.offer(node.right); - } - } - if (!t.isEmpty()) { - int j = 0, k = t.size() - 1; - for (; j < k; ++j, --k) { - int v = t.get(j).val; - t.get(j).val = t.get(k).val; - t.get(k).val = v; - } - } - ++i; - } - return root; - } +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + public TreeNode reverseOddLevels(TreeNode root) { + Deque q = new ArrayDeque<>(); + q.offer(root); + for (int i = 0; !q.isEmpty(); ++i) { + List t = new ArrayList<>(); + for (int k = q.size(); k > 0; --k) { + var node = q.poll(); + if (i % 2 == 1) { + t.add(node); + } + if (node.left != null) { + q.offer(node.left); + q.offer(node.right); + } + } + for (int l = 0, r = t.size() - 1; l < r; ++l, --r) { + var x = t.get(l).val; + t.get(l).val = t.get(r).val; + t.get(r).val = x; + } + } + return root; + } } \ No newline at end of file diff --git a/solution/2400-2499/2415.Reverse Odd Levels of Binary Tree/Solution.py b/solution/2400-2499/2415.Reverse Odd Levels of Binary Tree/Solution.py index b25586d22e82d..de4660157f546 100644 --- a/solution/2400-2499/2415.Reverse Odd Levels of Binary Tree/Solution.py +++ b/solution/2400-2499/2415.Reverse Odd Levels of Binary Tree/Solution.py @@ -1,27 +1,23 @@ -# Definition for a binary tree node. -# class TreeNode: -# def __init__(self, val=0, left=None, right=None): -# self.val = val -# self.left = left -# self.right = right -class Solution: - def reverseOddLevels(self, root: Optional[TreeNode]) -> Optional[TreeNode]: - q = deque([root]) - i = 0 - while q: - t = [] - for _ in range(len(q)): - node = q.popleft() - if i & 1: - t.append(node) - if node.left: - q.append(node.left) - if node.right: - q.append(node.right) - if t: - j, k = 0, len(t) - 1 - while j < k: - t[j].val, t[k].val = t[k].val, t[j].val - j, k = j + 1, k - 1 - i += 1 - return root +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def reverseOddLevels(self, root: Optional[TreeNode]) -> Optional[TreeNode]: + q = deque([root]) + i = 0 + while q: + if i & 1: + l, r = 0, len(q) - 1 + while l < r: + q[l].val, q[r].val = q[r].val, q[l].val + l, r = l + 1, r - 1 + for _ in range(len(q)): + node = q.popleft() + if node.left: + q.append(node.left) + q.append(node.right) + i += 1 + return root diff --git a/solution/2400-2499/2415.Reverse Odd Levels of Binary Tree/Solution.ts b/solution/2400-2499/2415.Reverse Odd Levels of Binary Tree/Solution.ts index 53e2b8292097b..5a246b3116209 100644 --- a/solution/2400-2499/2415.Reverse Odd Levels of Binary Tree/Solution.ts +++ b/solution/2400-2499/2415.Reverse Odd Levels of Binary Tree/Solution.ts @@ -13,24 +13,21 @@ */ function reverseOddLevels(root: TreeNode | null): TreeNode | null { - const queue = [root]; - let d = 0; - while (queue.length !== 0) { - const n = queue.length; - const t: TreeNode[] = []; - for (let i = 0; i < n; i++) { - const node = queue.shift(); - if (d % 2 == 1) { - t.push(node); + const q: TreeNode[] = [root]; + for (let i = 0; q.length > 0; ++i) { + if (i % 2) { + for (let l = 0, r = q.length - 1; l < r; ++l, --r) { + [q[l].val, q[r].val] = [q[r].val, q[l].val]; } - node.left && queue.push(node.left); - node.right && queue.push(node.right); } - const m = t.length; - for (let i = 0; i < m >> 1; i++) { - [t[i].val, t[m - 1 - i].val] = [t[m - 1 - i].val, t[i].val]; + const nq: TreeNode[] = []; + for (const { left, right } of q) { + if (left) { + nq.push(left); + nq.push(right); + } } - d++; + q.splice(0, q.length, ...nq); } return root; } diff --git a/solution/2900-2999/2960.Count Tested Devices After Test Operations/README.md b/solution/2900-2999/2960.Count Tested Devices After Test Operations/README.md index 9aa3117e069cb..dd792970396cd 100644 --- a/solution/2900-2999/2960.Count Tested Devices After Test Operations/README.md +++ b/solution/2900-2999/2960.Count Tested Devices After Test Operations/README.md @@ -66,7 +66,7 @@ **方法一:模拟** -假设我们当前已测试的设备数量为 $ans$,如果当测试新的一台设备 $i$ 时,它的剩余电量为 $\max(0, batteryPercentages[i] - ans)$,如果剩余电量大于 $0$,则说明这台设备可以进行测试,此时我们需要将 $ans$ 增加 $1$。 +假设我们当前已测试的设备数量为 $ans$,当测试新的一台设备 $i$ 时,它的剩余电量为 $\max(0, batteryPercentages[i] - ans)$,如果剩余电量大于 $0$,则说明这台设备可以进行测试,此时我们需要将 $ans$ 增加 $1$。 最后返回 $ans$ 即可。