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</div>
 
 <!-- solution:start -->
 
-### 方法一
+### 方法一:队列 + 哈希表 + 有序集合
+
+我们定义一个队列 $\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$ 为添加的数字的数量。
 
 <!-- tabs:start -->
 
@@ -159,13 +175,225 @@ class StatisticsTracker:
 #### Java
 
 ```java
-
+class MedianFinder {
+    private final PriorityQueue<Integer> small = new PriorityQueue<>(Comparator.reverseOrder());
+    private final PriorityQueue<Integer> large = new PriorityQueue<>();
+    private final Map<Integer, Integer> 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<Integer> 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<Integer> q = new ArrayDeque<>();
+    private long s;
+    private final Map<Integer, Integer> cnt = new HashMap<>();
+    private final MedianFinder medianFinder = new MedianFinder();
+    private final TreeSet<int[]> 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<int> small;
+    priority_queue<int, vector<int>, greater<int>> large;
+    unordered_map<int, int> delayed;
+    int smallSize = 0;
+    int largeSize = 0;
+
+    template <typename T>
+    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<int> q;
+    long long s = 0;
+    unordered_map<int, int> cnt;
+    MedianFinder medianFinder;
+    set<pair<int, int>> 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<int>(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</div>
 
 <!-- solution:start -->
 
-### 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.
 
 <!-- tabs:start -->
 
@@ -157,13 +173,225 @@ class StatisticsTracker:
 #### Java
 
 ```java
-
+class MedianFinder {
+    private final PriorityQueue<Integer> small = new PriorityQueue<>(Comparator.reverseOrder());
+    private final PriorityQueue<Integer> large = new PriorityQueue<>();
+    private final Map<Integer, Integer> 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<Integer> 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<Integer> q = new ArrayDeque<>();
+    private long s;
+    private final Map<Integer, Integer> cnt = new HashMap<>();
+    private final MedianFinder medianFinder = new MedianFinder();
+    private final TreeSet<int[]> 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<int> small;
+    priority_queue<int, vector<int>, greater<int>> large;
+    unordered_map<int, int> delayed;
+    int smallSize = 0;
+    int largeSize = 0;
+
+    template <typename T>
+    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<int> q;
+    long long s = 0;
+    unordered_map<int, int> cnt;
+    MedianFinder medianFinder;
+    set<pair<int, int>> 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<int>(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<int> small;
+    priority_queue<int, vector<int>, greater<int>> large;
+    unordered_map<int, int> delayed;
+    int smallSize = 0;
+    int largeSize = 0;
+
+    template <typename T>
+    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<int> q;
+    long long s = 0;
+    unordered_map<int, int> cnt;
+    MedianFinder medianFinder;
+    set<pair<int, int>> 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<int>(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<Integer> small = new PriorityQueue<>(Comparator.reverseOrder());
+    private final PriorityQueue<Integer> large = new PriorityQueue<>();
+    private final Map<Integer, Integer> 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<Integer> 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<Integer> q = new ArrayDeque<>();
+    private long s;
+    private final Map<Integer, Integer> cnt = new HashMap<>();
+    private final MedianFinder medianFinder = new MedianFinder();
+    private final TreeSet<int[]> 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:
 
 <!-- solution:start -->
 
-### 方法一
+### 方法一:位运算
+
+我们从 $x = 1$ 开始,不断将 $x$ 左移,直到 $x - 1 \geq n$,此时 $x - 1$ 就是我们要找的答案。
+
+时间复杂度 $O(\log n)$,空间复杂度 $O(1)$。
 
 <!-- tabs:start -->
 
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:start -->
 
-### 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)$.
 
 <!-- tabs:start -->
 
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:
 
 <!-- solution:start -->
 
-### 方法一
+### 方法一:哈希表 + 枚举
+
+我们用一个哈希表 $\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}$ 的长度。
 
 <!-- tabs:start -->
 
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:start -->
 
-### 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}$.
 
 <!-- tabs:start -->
 
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:
 
 <!-- solution:start -->
 
-### 方法一
+### 方法一:枚举 + DFS
+
+根据题目描述,要使得节点 $i$ 的目标节点数目最大,对于第 $i$ 个节点,我们一定会选择该节点与第二棵树中的其中一个节点 $j$ 相连,因此,节点 $i$ 的目标节点数可以分成两部分计算:
+
+-   在第一棵树中,从节点 $i$ 出发,深度不超过 $k$ 的节点数目;
+-   在第二棵树中,从任意节点 $j$ 出发,深度不超过 $k - 1$ 的节点数目,取最大值。
+
+因此,我们可以先计算第二棵树中每个节点的深度不超过 $k - 1$ 的节点数目,然后枚举第一棵树中的每个节点 $i$,计算上述两部分的和,取最大值即可。
+
+时间复杂度 $O(n^2 + m^2)$,空间复杂度 $O(n + m)$。其中 $n$ 和 $m$ 分别为两棵树的节点数。
 
 <!-- tabs:start -->
 
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:start -->
 
-### 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.
 
 <!-- tabs:start -->
 
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:
 
 <!-- solution:start -->
 
-### 方法一
+### 方法一:DFS
+
+节点 $i$ 的目标节点数可以分成两部分计算:
+
+-   第一棵树中与节点 $i$ 的深度奇偶性相同的节点数;
+-   第二棵树中深度奇偶性相同的节点数的最大值。
+
+我们先通过深度优先搜索,计算出第二棵树中深度奇偶性相同的节点数,记为 $\textit{cnt2}$,然后再计算第一棵树中与节点 $i$ 的深度奇偶性相同的节点数,记为 $\textit{cnt1}$,那么节点 $i$ 的目标节点数就是 $\max(\textit{cnt2}) + \textit{cnt1}$。
+
+时间复杂度 $O(n + m)$,空间复杂度 $O(n + m)$。其中 $n$ 和 $m$ 分别是第一棵树和第二棵树的节点数。
 
 <!-- tabs:start -->
 
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:start -->
 
-### 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.
 
 <!-- tabs:start -->