diff --git a/solution/3300-3399/3369.Design an Array Statistics Tracker/README.md b/solution/3300-3399/3369.Design an Array Statistics Tracker/README.md index 600d9f2fd9b7b..ea1bedc26c2bd 100644 --- a/solution/3300-3399/3369.Design an Array Statistics Tracker/README.md +++ b/solution/3300-3399/3369.Design an Array Statistics Tracker/README.md @@ -102,7 +102,23 @@ statisticsTracker.getMode(); // return 5 -### 方法一 +### 方法一:队列 + 哈希表 + 有序集合 + +我们定义一个队列 $\textit{q}$,用来存储添加的数字,一个变量 $\textit{s}$,用来存储所有数字的和,一个哈希表 $\textit{cnt}$,用来存储每个数字的出现次数,一个有序集合 $\textit{sl}$,用来存储所有数字,一个有序集合 $\textit{sl2}$,用来存储所有数字及其出现次数,按照出现次数降序、数值升序的顺序。 + +在 `addNumber` 方法中,我们将数字添加到队列 $\textit{q}$ 中,将数字添加到有序集合 $\textit{sl}$ 中,然后先将数字及其出现次数从有序集合 $\textit{sl2}$ 中删除,再更新数字的出现次数,最后将数字及其出现次数添加到有序集合 $\textit{sl2}$ 中,并更新所有数字的和。时间复杂度为 $O(\log n)$。 + +在 `removeFirstAddedNumber` 方法中,我们从队列 $\textit{q}$ 中删除最早添加的数字,从有序集合 $\textit{sl}$ 中删除数字,然后先将数字及其出现次数从有序集合 $\textit{sl2}$ 中删除,再更新数字的出现次数,最后将数字及其出现次数添加到有序集合 $\textit{sl2}$ 中,并更新所有数字的和。时间复杂度为 $O(\log n)$。 + +在 `getMean` 方法中,我们返回所有数字的和除以数字的数量,时间复杂度为 $O(1)$。 + +在 `getMedian` 方法中,我们返回有序集合 $\textit{sl}$ 中的第 $\textit{len}(\textit{q}) / 2$ 个数字,时间复杂度为 $O(1)$ 或 $O(\log n)$。 + +在 `getMode` 方法中,我们返回有序集合 $\textit{sl2}$ 中的第一个数字,时间复杂度 $O(1)$。 + +> 在 Python 中,我们可以直接按下标获取有序集合中的元素,在其它语言中,我们可以通过对顶堆实现。 + +空间复杂度 $O(n)$,其中 $n$ 为添加的数字的数量。 @@ -159,13 +175,225 @@ class StatisticsTracker: #### Java ```java - +class MedianFinder { + private final PriorityQueue small = new PriorityQueue<>(Comparator.reverseOrder()); + private final PriorityQueue large = new PriorityQueue<>(); + private final Map delayed = new HashMap<>(); + private int smallSize; + private int largeSize; + + public void addNum(int num) { + if (small.isEmpty() || num <= small.peek()) { + small.offer(num); + ++smallSize; + } else { + large.offer(num); + ++largeSize; + } + rebalance(); + } + + public Integer findMedian() { + return smallSize == largeSize ? large.peek() : small.peek(); + } + + public void removeNum(int num) { + delayed.merge(num, 1, Integer::sum); + if (num <= small.peek()) { + --smallSize; + if (num == small.peek()) { + prune(small); + } + } else { + --largeSize; + if (num == large.peek()) { + prune(large); + } + } + rebalance(); + } + + private void prune(PriorityQueue pq) { + while (!pq.isEmpty() && delayed.containsKey(pq.peek())) { + if (delayed.merge(pq.peek(), -1, Integer::sum) == 0) { + delayed.remove(pq.peek()); + } + pq.poll(); + } + } + + private void rebalance() { + if (smallSize > largeSize + 1) { + large.offer(small.poll()); + --smallSize; + ++largeSize; + prune(small); + } else if (smallSize < largeSize) { + small.offer(large.poll()); + --largeSize; + ++smallSize; + prune(large); + } + } +} + +class StatisticsTracker { + private final Deque q = new ArrayDeque<>(); + private long s; + private final Map cnt = new HashMap<>(); + private final MedianFinder medianFinder = new MedianFinder(); + private final TreeSet ts + = new TreeSet<>((a, b) -> a[1] == b[1] ? a[0] - b[0] : b[1] - a[1]); + + public StatisticsTracker() { + } + + public void addNumber(int number) { + q.offerLast(number); + s += number; + ts.remove(new int[] {number, cnt.getOrDefault(number, 0)}); + cnt.merge(number, 1, Integer::sum); + medianFinder.addNum(number); + ts.add(new int[] {number, cnt.get(number)}); + } + + public void removeFirstAddedNumber() { + int number = q.pollFirst(); + s -= number; + ts.remove(new int[] {number, cnt.get(number)}); + cnt.merge(number, -1, Integer::sum); + medianFinder.removeNum(number); + ts.add(new int[] {number, cnt.get(number)}); + } + + public int getMean() { + return (int) (s / q.size()); + } + + public int getMedian() { + return medianFinder.findMedian(); + } + + public int getMode() { + return ts.first()[0]; + } +} ``` #### C++ ```cpp - +class MedianFinder { +public: + void addNum(int num) { + if (small.empty() || num <= small.top()) { + small.push(num); + ++smallSize; + } else { + large.push(num); + ++largeSize; + } + reblance(); + } + + void removeNum(int num) { + ++delayed[num]; + if (num <= small.top()) { + --smallSize; + if (num == small.top()) { + prune(small); + } + } else { + --largeSize; + if (num == large.top()) { + prune(large); + } + } + reblance(); + } + + int findMedian() { + return smallSize == largeSize ? large.top() : small.top(); + } + +private: + priority_queue small; + priority_queue, greater> large; + unordered_map delayed; + int smallSize = 0; + int largeSize = 0; + + template + void prune(T& pq) { + while (!pq.empty() && delayed[pq.top()]) { + if (--delayed[pq.top()] == 0) { + delayed.erase(pq.top()); + } + pq.pop(); + } + } + + void reblance() { + if (smallSize > largeSize + 1) { + large.push(small.top()); + small.pop(); + --smallSize; + ++largeSize; + prune(small); + } else if (smallSize < largeSize) { + small.push(large.top()); + large.pop(); + ++smallSize; + --largeSize; + prune(large); + } + } +}; + +class StatisticsTracker { +private: + queue q; + long long s = 0; + unordered_map cnt; + MedianFinder medianFinder; + set> ts; + +public: + StatisticsTracker() {} + + void addNumber(int number) { + q.push(number); + s += number; + ts.erase({-cnt[number], number}); + cnt[number]++; + medianFinder.addNum(number); + ts.insert({-cnt[number], number}); + } + + void removeFirstAddedNumber() { + int number = q.front(); + q.pop(); + s -= number; + ts.erase({-cnt[number], number}); + cnt[number]--; + if (cnt[number] > 0) { + ts.insert({-cnt[number], number}); + } + medianFinder.removeNum(number); + } + + int getMean() { + return static_cast(s / q.size()); + } + + int getMedian() { + return medianFinder.findMedian(); + } + + int getMode() { + return ts.begin()->second; + } +}; ``` #### Go diff --git a/solution/3300-3399/3369.Design an Array Statistics Tracker/README_EN.md b/solution/3300-3399/3369.Design an Array Statistics Tracker/README_EN.md index 1ac13e751cb9b..4ac3c14827b39 100644 --- a/solution/3300-3399/3369.Design an Array Statistics Tracker/README_EN.md +++ b/solution/3300-3399/3369.Design an Array Statistics Tracker/README_EN.md @@ -100,7 +100,23 @@ statisticsTracker.getMode(); // return 5 -### Solution 1 +### Solution 1: Queue + Hash Table + Ordered Set + +We define a queue $\textit{q}$ to store the added numbers, a variable $\textit{s}$ to store the sum of all numbers, a hash table $\textit{cnt}$ to store the occurrence count of each number, an ordered set $\textit{sl}$ to store all numbers, and an ordered set $\textit{sl2}$ to store all numbers and their occurrence counts, sorted by occurrence count in descending order and by value in ascending order. + +In the `addNumber` method, we add the number to the queue $\textit{q}$, add the number to the ordered set $\textit{sl}$, then remove the number and its occurrence count from the ordered set $\textit{sl2}$, update the occurrence count of the number, and finally add the number and its updated occurrence count to the ordered set $\textit{sl2}$, and update the sum of all numbers. The time complexity is $O(\log n)$. + +In the `removeFirstAddedNumber` method, we remove the earliest added number from the queue $\textit{q}$, remove the number from the ordered set $\textit{sl}$, then remove the number and its occurrence count from the ordered set $\textit{sl2}$, update the occurrence count of the number, and finally add the number and its updated occurrence count to the ordered set $\textit{sl2}$, and update the sum of all numbers. The time complexity is $O(\log n)$. + +In the `getMean` method, we return the sum of all numbers divided by the number of numbers. The time complexity is $O(1)$. + +In the `getMedian` method, we return the $\textit{len}(\textit{q}) / 2$-th number in the ordered set $\textit{sl}$. The time complexity is $O(1)$ or $O(\log n)$. + +In the `getMode` method, we return the first number in the ordered set $\textit{sl2}$. The time complexity is $O(1)$. + +> In Python, we can directly access elements in an ordered set by index. In other languages, we can implement this using a heap. + +The space complexity is $O(n)$, where $n$ is the number of added numbers. @@ -157,13 +173,225 @@ class StatisticsTracker: #### Java ```java - +class MedianFinder { + private final PriorityQueue small = new PriorityQueue<>(Comparator.reverseOrder()); + private final PriorityQueue large = new PriorityQueue<>(); + private final Map delayed = new HashMap<>(); + private int smallSize; + private int largeSize; + + public void addNum(int num) { + if (small.isEmpty() || num <= small.peek()) { + small.offer(num); + ++smallSize; + } else { + large.offer(num); + ++largeSize; + } + rebalance(); + } + + public Integer findMedian() { + return smallSize == largeSize ? large.peek() : small.peek(); + } + + public void removeNum(int num) { + delayed.merge(num, 1, Integer::sum); + if (num <= small.peek()) { + --smallSize; + if (num == small.peek()) { + prune(small); + } + } else { + --largeSize; + if (num == large.peek()) { + prune(large); + } + } + rebalance(); + } + + private void prune(PriorityQueue pq) { + while (!pq.isEmpty() && delayed.containsKey(pq.peek())) { + if (delayed.merge(pq.peek(), -1, Integer::sum) == 0) { + delayed.remove(pq.peek()); + } + pq.poll(); + } + } + + private void rebalance() { + if (smallSize > largeSize + 1) { + large.offer(small.poll()); + --smallSize; + ++largeSize; + prune(small); + } else if (smallSize < largeSize) { + small.offer(large.poll()); + --largeSize; + ++smallSize; + prune(large); + } + } +} + +class StatisticsTracker { + private final Deque q = new ArrayDeque<>(); + private long s; + private final Map cnt = new HashMap<>(); + private final MedianFinder medianFinder = new MedianFinder(); + private final TreeSet ts + = new TreeSet<>((a, b) -> a[1] == b[1] ? a[0] - b[0] : b[1] - a[1]); + + public StatisticsTracker() { + } + + public void addNumber(int number) { + q.offerLast(number); + s += number; + ts.remove(new int[] {number, cnt.getOrDefault(number, 0)}); + cnt.merge(number, 1, Integer::sum); + medianFinder.addNum(number); + ts.add(new int[] {number, cnt.get(number)}); + } + + public void removeFirstAddedNumber() { + int number = q.pollFirst(); + s -= number; + ts.remove(new int[] {number, cnt.get(number)}); + cnt.merge(number, -1, Integer::sum); + medianFinder.removeNum(number); + ts.add(new int[] {number, cnt.get(number)}); + } + + public int getMean() { + return (int) (s / q.size()); + } + + public int getMedian() { + return medianFinder.findMedian(); + } + + public int getMode() { + return ts.first()[0]; + } +} ``` #### C++ ```cpp - +class MedianFinder { +public: + void addNum(int num) { + if (small.empty() || num <= small.top()) { + small.push(num); + ++smallSize; + } else { + large.push(num); + ++largeSize; + } + reblance(); + } + + void removeNum(int num) { + ++delayed[num]; + if (num <= small.top()) { + --smallSize; + if (num == small.top()) { + prune(small); + } + } else { + --largeSize; + if (num == large.top()) { + prune(large); + } + } + reblance(); + } + + int findMedian() { + return smallSize == largeSize ? large.top() : small.top(); + } + +private: + priority_queue small; + priority_queue, greater> large; + unordered_map delayed; + int smallSize = 0; + int largeSize = 0; + + template + void prune(T& pq) { + while (!pq.empty() && delayed[pq.top()]) { + if (--delayed[pq.top()] == 0) { + delayed.erase(pq.top()); + } + pq.pop(); + } + } + + void reblance() { + if (smallSize > largeSize + 1) { + large.push(small.top()); + small.pop(); + --smallSize; + ++largeSize; + prune(small); + } else if (smallSize < largeSize) { + small.push(large.top()); + large.pop(); + ++smallSize; + --largeSize; + prune(large); + } + } +}; + +class StatisticsTracker { +private: + queue q; + long long s = 0; + unordered_map cnt; + MedianFinder medianFinder; + set> ts; + +public: + StatisticsTracker() {} + + void addNumber(int number) { + q.push(number); + s += number; + ts.erase({-cnt[number], number}); + cnt[number]++; + medianFinder.addNum(number); + ts.insert({-cnt[number], number}); + } + + void removeFirstAddedNumber() { + int number = q.front(); + q.pop(); + s -= number; + ts.erase({-cnt[number], number}); + cnt[number]--; + if (cnt[number] > 0) { + ts.insert({-cnt[number], number}); + } + medianFinder.removeNum(number); + } + + int getMean() { + return static_cast(s / q.size()); + } + + int getMedian() { + return medianFinder.findMedian(); + } + + int getMode() { + return ts.begin()->second; + } +}; ``` #### Go diff --git a/solution/3300-3399/3369.Design an Array Statistics Tracker/Solution.cpp b/solution/3300-3399/3369.Design an Array Statistics Tracker/Solution.cpp new file mode 100644 index 0000000000000..eead7a5d8b68f --- /dev/null +++ b/solution/3300-3399/3369.Design an Array Statistics Tracker/Solution.cpp @@ -0,0 +1,111 @@ +class MedianFinder { +public: + void addNum(int num) { + if (small.empty() || num <= small.top()) { + small.push(num); + ++smallSize; + } else { + large.push(num); + ++largeSize; + } + reblance(); + } + + void removeNum(int num) { + ++delayed[num]; + if (num <= small.top()) { + --smallSize; + if (num == small.top()) { + prune(small); + } + } else { + --largeSize; + if (num == large.top()) { + prune(large); + } + } + reblance(); + } + + int findMedian() { + return smallSize == largeSize ? large.top() : small.top(); + } + +private: + priority_queue small; + priority_queue, greater> large; + unordered_map delayed; + int smallSize = 0; + int largeSize = 0; + + template + void prune(T& pq) { + while (!pq.empty() && delayed[pq.top()]) { + if (--delayed[pq.top()] == 0) { + delayed.erase(pq.top()); + } + pq.pop(); + } + } + + void reblance() { + if (smallSize > largeSize + 1) { + large.push(small.top()); + small.pop(); + --smallSize; + ++largeSize; + prune(small); + } else if (smallSize < largeSize) { + small.push(large.top()); + large.pop(); + ++smallSize; + --largeSize; + prune(large); + } + } +}; + +class StatisticsTracker { +private: + queue q; + long long s = 0; + unordered_map cnt; + MedianFinder medianFinder; + set> ts; + +public: + StatisticsTracker() {} + + void addNumber(int number) { + q.push(number); + s += number; + ts.erase({-cnt[number], number}); + cnt[number]++; + medianFinder.addNum(number); + ts.insert({-cnt[number], number}); + } + + void removeFirstAddedNumber() { + int number = q.front(); + q.pop(); + s -= number; + ts.erase({-cnt[number], number}); + cnt[number]--; + if (cnt[number] > 0) { + ts.insert({-cnt[number], number}); + } + medianFinder.removeNum(number); + } + + int getMean() { + return static_cast(s / q.size()); + } + + int getMedian() { + return medianFinder.findMedian(); + } + + int getMode() { + return ts.begin()->second; + } +}; diff --git a/solution/3300-3399/3369.Design an Array Statistics Tracker/Solution.java b/solution/3300-3399/3369.Design an Array Statistics Tracker/Solution.java new file mode 100644 index 0000000000000..995dff487ac02 --- /dev/null +++ b/solution/3300-3399/3369.Design an Array Statistics Tracker/Solution.java @@ -0,0 +1,103 @@ +class MedianFinder { + private final PriorityQueue small = new PriorityQueue<>(Comparator.reverseOrder()); + private final PriorityQueue large = new PriorityQueue<>(); + private final Map delayed = new HashMap<>(); + private int smallSize; + private int largeSize; + + public void addNum(int num) { + if (small.isEmpty() || num <= small.peek()) { + small.offer(num); + ++smallSize; + } else { + large.offer(num); + ++largeSize; + } + rebalance(); + } + + public Integer findMedian() { + return smallSize == largeSize ? large.peek() : small.peek(); + } + + public void removeNum(int num) { + delayed.merge(num, 1, Integer::sum); + if (num <= small.peek()) { + --smallSize; + if (num == small.peek()) { + prune(small); + } + } else { + --largeSize; + if (num == large.peek()) { + prune(large); + } + } + rebalance(); + } + + private void prune(PriorityQueue pq) { + while (!pq.isEmpty() && delayed.containsKey(pq.peek())) { + if (delayed.merge(pq.peek(), -1, Integer::sum) == 0) { + delayed.remove(pq.peek()); + } + pq.poll(); + } + } + + private void rebalance() { + if (smallSize > largeSize + 1) { + large.offer(small.poll()); + --smallSize; + ++largeSize; + prune(small); + } else if (smallSize < largeSize) { + small.offer(large.poll()); + --largeSize; + ++smallSize; + prune(large); + } + } +} + +class StatisticsTracker { + private final Deque q = new ArrayDeque<>(); + private long s; + private final Map cnt = new HashMap<>(); + private final MedianFinder medianFinder = new MedianFinder(); + private final TreeSet ts + = new TreeSet<>((a, b) -> a[1] == b[1] ? a[0] - b[0] : b[1] - a[1]); + + public StatisticsTracker() { + } + + public void addNumber(int number) { + q.offerLast(number); + s += number; + ts.remove(new int[] {number, cnt.getOrDefault(number, 0)}); + cnt.merge(number, 1, Integer::sum); + medianFinder.addNum(number); + ts.add(new int[] {number, cnt.get(number)}); + } + + public void removeFirstAddedNumber() { + int number = q.pollFirst(); + s -= number; + ts.remove(new int[] {number, cnt.get(number)}); + cnt.merge(number, -1, Integer::sum); + medianFinder.removeNum(number); + ts.add(new int[] {number, cnt.get(number)}); + } + + public int getMean() { + return (int) (s / q.size()); + } + + public int getMedian() { + return medianFinder.findMedian(); + } + + public int getMode() { + return ts.first()[0]; + } +} diff --git a/solution/3300-3399/3370.Smallest Number With All Set Bits/README.md b/solution/3300-3399/3370.Smallest Number With All Set Bits/README.md index 7f19592c20e27..fc7fe3b5d4f8b 100644 --- a/solution/3300-3399/3370.Smallest Number With All Set Bits/README.md +++ b/solution/3300-3399/3370.Smallest Number With All Set Bits/README.md @@ -75,7 +75,11 @@ tags: -### 方法一 +### 方法一:位运算 + +我们从 $x = 1$ 开始,不断将 $x$ 左移,直到 $x - 1 \geq n$,此时 $x - 1$ 就是我们要找的答案。 + +时间复杂度 $O(\log n)$,空间复杂度 $O(1)$。 diff --git a/solution/3300-3399/3370.Smallest Number With All Set Bits/README_EN.md b/solution/3300-3399/3370.Smallest Number With All Set Bits/README_EN.md index 8db2b834e92dc..0918bb0b77a90 100644 --- a/solution/3300-3399/3370.Smallest Number With All Set Bits/README_EN.md +++ b/solution/3300-3399/3370.Smallest Number With All Set Bits/README_EN.md @@ -73,7 +73,11 @@ tags: -### Solution 1 +### Solution 1: Bit Manipulation + +We start with $x = 1$ and continuously left shift $x$ until $x - 1 \geq n$. At this point, $x - 1$ is the answer we are looking for. + +The time complexity is $O(\log n)$, and the space complexity is $O(1)$. diff --git a/solution/3300-3399/3371.Identify the Largest Outlier in an Array/README.md b/solution/3300-3399/3371.Identify the Largest Outlier in an Array/README.md index 0cb3625e952d9..00253239e04c0 100644 --- a/solution/3300-3399/3371.Identify the Largest Outlier in an Array/README.md +++ b/solution/3300-3399/3371.Identify the Largest Outlier in an Array/README.md @@ -81,7 +81,15 @@ tags: -### 方法一 +### 方法一:哈希表 + 枚举 + +我们用一个哈希表 $\textit{cnt}$ 记录数组 $\textit{nums}$ 中每个元素出现的次数。 + +接下来,我们枚举数组 $\textit{nums}$ 中的每个元素 $x$ 作为可能的异常值,对于每个 $x$,我们计算数组 $\textit{nums}$ 中除了 $x$ 之外的所有元素的和 $t$,如果 $t$ 不是偶数,或者 $t$ 的一半不在 $\textit{cnt}$ 中,那么 $x$ 不满足条件,我们跳过这个 $x$。否则,如果 $x$ 不等于 $t$ 的一半,或者 $x$ 在 $\textit{cnt}$ 中出现的次数大于 $1$,那么 $x$ 是一个可能的异常值,我们更新答案。 + +枚举结束后,返回答案即可。 + +时间复杂度 $O(n)$,空间复杂度 $O(n)$。其中 $n$ 为数组 $\textit{nums}$ 的长度。 diff --git a/solution/3300-3399/3371.Identify the Largest Outlier in an Array/README_EN.md b/solution/3300-3399/3371.Identify the Largest Outlier in an Array/README_EN.md index 467f57b5ce8a0..515e8c5f034cd 100644 --- a/solution/3300-3399/3371.Identify the Largest Outlier in an Array/README_EN.md +++ b/solution/3300-3399/3371.Identify the Largest Outlier in an Array/README_EN.md @@ -79,7 +79,15 @@ tags: -### Solution 1 +### Solution 1: Hash Table + Enumeration + +We use a hash table $\textit{cnt}$ to record the frequency of each element in the array $\textit{nums}$. + +Next, we enumerate each element $x$ in the array $\textit{nums}$ as a possible outlier. For each $x$, we calculate the sum $t$ of all elements in the array $\textit{nums}$ except $x$. If $t$ is not even, or half of $t$ is not in $\textit{cnt}$, then $x$ does not meet the condition, and we skip this $x$. Otherwise, if $x$ is not equal to half of $t$, or $x$ appears more than once in $\textit{cnt}$, then $x$ is a possible outlier, and we update the answer. + +After enumerating all elements, we return the answer. + +The time complexity is $O(n)$, and the space complexity is $O(n)$. Here, $n$ is the length of the array $\textit{nums}$. diff --git a/solution/3300-3399/3372.Maximize the Number of Target Nodes After Connecting Trees I/README.md b/solution/3300-3399/3372.Maximize the Number of Target Nodes After Connecting Trees I/README.md index aee522ce46e03..af89e57e1440d 100644 --- a/solution/3300-3399/3372.Maximize the Number of Target Nodes After Connecting Trees I/README.md +++ b/solution/3300-3399/3372.Maximize the Number of Target Nodes After Connecting Trees I/README.md @@ -86,7 +86,16 @@ tags: -### 方法一 +### 方法一:枚举 + DFS + +根据题目描述,要使得节点 $i$ 的目标节点数目最大,对于第 $i$ 个节点,我们一定会选择该节点与第二棵树中的其中一个节点 $j$ 相连,因此,节点 $i$ 的目标节点数可以分成两部分计算: + +- 在第一棵树中,从节点 $i$ 出发,深度不超过 $k$ 的节点数目; +- 在第二棵树中,从任意节点 $j$ 出发,深度不超过 $k - 1$ 的节点数目,取最大值。 + +因此,我们可以先计算第二棵树中每个节点的深度不超过 $k - 1$ 的节点数目,然后枚举第一棵树中的每个节点 $i$,计算上述两部分的和,取最大值即可。 + +时间复杂度 $O(n^2 + m^2)$,空间复杂度 $O(n + m)$。其中 $n$ 和 $m$ 分别为两棵树的节点数。 diff --git a/solution/3300-3399/3372.Maximize the Number of Target Nodes After Connecting Trees I/README_EN.md b/solution/3300-3399/3372.Maximize the Number of Target Nodes After Connecting Trees I/README_EN.md index dcd91a4fbcac1..fac8eacd7f9ac 100644 --- a/solution/3300-3399/3372.Maximize the Number of Target Nodes After Connecting Trees I/README_EN.md +++ b/solution/3300-3399/3372.Maximize the Number of Target Nodes After Connecting Trees I/README_EN.md @@ -81,7 +81,16 @@ tags: -### Solution 1 +### Solution 1: Enumeration + DFS + +According to the problem description, to maximize the number of target nodes for node $i$, we must connect node $i$ to one of the nodes $j$ in the second tree. Therefore, the number of target nodes for node $i$ can be divided into two parts: + +- In the first tree, the number of nodes reachable from node $i$ within a depth of $k$. +- In the second tree, the maximum number of nodes reachable from any node $j$ within a depth of $k - 1$. + +Thus, we can first calculate the number of nodes reachable within a depth of $k - 1$ for each node in the second tree. Then, we enumerate each node $i$ in the first tree, calculate the sum of the two parts mentioned above, and take the maximum value. + +The time complexity is $O(n^2 + m^2)$, and the space complexity is $O(n + m)$. Here, $n$ and $m$ are the number of nodes in the two trees, respectively. diff --git a/solution/3300-3399/3373.Maximize the Number of Target Nodes After Connecting Trees II/README.md b/solution/3300-3399/3373.Maximize the Number of Target Nodes After Connecting Trees II/README.md index a6bef2a9f92fa..b9f7280f3f152 100644 --- a/solution/3300-3399/3373.Maximize the Number of Target Nodes After Connecting Trees II/README.md +++ b/solution/3300-3399/3373.Maximize the Number of Target Nodes After Connecting Trees II/README.md @@ -85,7 +85,16 @@ tags: -### 方法一 +### 方法一:DFS + +节点 $i$ 的目标节点数可以分成两部分计算: + +- 第一棵树中与节点 $i$ 的深度奇偶性相同的节点数; +- 第二棵树中深度奇偶性相同的节点数的最大值。 + +我们先通过深度优先搜索,计算出第二棵树中深度奇偶性相同的节点数,记为 $\textit{cnt2}$,然后再计算第一棵树中与节点 $i$ 的深度奇偶性相同的节点数,记为 $\textit{cnt1}$,那么节点 $i$ 的目标节点数就是 $\max(\textit{cnt2}) + \textit{cnt1}$。 + +时间复杂度 $O(n + m)$,空间复杂度 $O(n + m)$。其中 $n$ 和 $m$ 分别是第一棵树和第二棵树的节点数。 diff --git a/solution/3300-3399/3373.Maximize the Number of Target Nodes After Connecting Trees II/README_EN.md b/solution/3300-3399/3373.Maximize the Number of Target Nodes After Connecting Trees II/README_EN.md index 3ee12e3bf90e0..fdf44bd2bd18c 100644 --- a/solution/3300-3399/3373.Maximize the Number of Target Nodes After Connecting Trees II/README_EN.md +++ b/solution/3300-3399/3373.Maximize the Number of Target Nodes After Connecting Trees II/README_EN.md @@ -80,7 +80,16 @@ tags: -### Solution 1 +### Solution 1: DFS + +The number of target nodes for node $i$ can be divided into two parts: + +- The number of nodes in the first tree with the same depth parity as node $i$. +- The maximum number of nodes in the second tree with the same depth parity. + +First, we use Depth-First Search (DFS) to calculate the number of nodes in the second tree with the same depth parity, denoted as $\textit{cnt2}$. Then, we calculate the number of nodes in the first tree with the same depth parity as node $i$, denoted as $\textit{cnt1}$. Therefore, the number of target nodes for node $i$ is $\max(\textit{cnt2}) + \textit{cnt1}$. + +The time complexity is $O(n + m)$, and the space complexity is $O(n + m)$. Here, $n$ and $m$ are the number of nodes in the first and second trees, respectively.