diff --git a/solution/3400-3499/3433.Count Mentions Per User/README.md b/solution/3400-3499/3433.Count Mentions Per User/README.md index b6f1d55587f17..3dfa73e8adbd8 100644 --- a/solution/3400-3499/3433.Count Mentions Per User/README.md +++ b/solution/3400-3499/3433.Count Mentions Per User/README.md @@ -126,32 +126,252 @@ tags: -### 方法一 +### 方法一:排序 + 模拟 + +我们将事件按照时间戳升序排序,如果时间戳相同,我们将 OFFLINE 事件排在 MESSAGE 事件之前。 + +然后我们模拟事件的发生过程,使用 `online_t` 数组记录每个用户下一次上线的时间,用一个变量 `lazy` 记录所有用户还需要被提及的次数。 + +遍历事件列表,根据事件类型进行处理: + +- 如果是 ONLINE 事件,我们更新 `online_t` 数组; +- 如果是 ALL 事件,我们将 `lazy` 加一; +- 如果是 HERE 事件,我们遍历 `online_t` 数组,如果用户下一次上线的时间小于等于当前时间,我们将该用户的提及次数加一; +- 如果是 MESSAGE 事件,我们将提及的用户的提及次数加一。 + +最后,如果 `lazy` 大于 0,我们将所有用户的提及次数加上 `lazy`。 + +时间复杂度 $O(n + m \times \log m \log M + L)$,空间复杂度 $O(n)$。其中 $n$ 和 $m$ 分别是用户总数和事件总数,而 $M$ 和 $L$ 分别是时间戳的最大值以及所有提及的字符串的总长度。 #### Python3 ```python - +class Solution: + def countMentions(self, numberOfUsers: int, events: List[List[str]]) -> List[int]: + events.sort(key=lambda e: (int(e[1]), e[0][2])) + ans = [0] * numberOfUsers + online_t = [0] * numberOfUsers + lazy = 0 + for etype, ts, s in events: + cur = int(ts) + if etype[0] == "O": + online_t[int(s)] = cur + 60 + elif s[0] == "A": + lazy += 1 + elif s[0] == "H": + for i, t in enumerate(online_t): + if t <= cur: + ans[i] += 1 + else: + for a in s.split(): + ans[int(a[2:])] += 1 + if lazy: + for i in range(numberOfUsers): + ans[i] += lazy + return ans ``` #### Java ```java - +class Solution { + public int[] countMentions(int numberOfUsers, List> events) { + events.sort((a, b) -> { + int x = Integer.parseInt(a.get(1)); + int y = Integer.parseInt(b.get(1)); + if (x == y) { + return a.get(0).charAt(2) - b.get(0).charAt(2); + } + return x - y; + }); + int[] ans = new int[numberOfUsers]; + int[] onlineT = new int[numberOfUsers]; + int lazy = 0; + for (var e : events) { + String etype = e.get(0); + int cur = Integer.parseInt(e.get(1)); + String s = e.get(2); + if (etype.charAt(0) == 'O') { + onlineT[Integer.parseInt(s)] = cur + 60; + } else if (s.charAt(0) == 'A') { + ++lazy; + } else if (s.charAt(0) == 'H') { + for (int i = 0; i < numberOfUsers; ++i) { + if (onlineT[i] <= cur) { + ++ans[i]; + } + } + } else { + for (var a : s.split(" ")) { + ++ans[Integer.parseInt(a.substring(2))]; + } + } + } + if (lazy > 0) { + for (int i = 0; i < numberOfUsers; ++i) { + ans[i] += lazy; + } + } + return ans; + } +} ``` #### C++ ```cpp - +class Solution { +public: + vector countMentions(int numberOfUsers, vector>& events) { + ranges::sort(events, [](const vector& a, const vector& b) { + int x = stoi(a[1]); + int y = stoi(b[1]); + if (x == y) { + return a[0][2] < b[0][2]; + } + return x < y; + }); + + vector ans(numberOfUsers, 0); + vector onlineT(numberOfUsers, 0); + int lazy = 0; + + for (const auto& e : events) { + string etype = e[0]; + int cur = stoi(e[1]); + string s = e[2]; + + if (etype[0] == 'O') { + onlineT[stoi(s)] = cur + 60; + } else if (s[0] == 'A') { + lazy++; + } else if (s[0] == 'H') { + for (int i = 0; i < numberOfUsers; ++i) { + if (onlineT[i] <= cur) { + ++ans[i]; + } + } + } else { + stringstream ss(s); + string token; + while (ss >> token) { + ans[stoi(token.substr(2))]++; + } + } + } + + if (lazy > 0) { + for (int i = 0; i < numberOfUsers; ++i) { + ans[i] += lazy; + } + } + + return ans; + } +}; ``` #### Go ```go +func countMentions(numberOfUsers int, events [][]string) []int { + sort.Slice(events, func(i, j int) bool { + x, _ := strconv.Atoi(events[i][1]) + y, _ := strconv.Atoi(events[j][1]) + if x == y { + return events[i][0][2] < events[j][0][2] + } + return x < y + }) + + ans := make([]int, numberOfUsers) + onlineT := make([]int, numberOfUsers) + lazy := 0 + + for _, e := range events { + etype := e[0] + cur, _ := strconv.Atoi(e[1]) + s := e[2] + + if etype[0] == 'O' { + userID, _ := strconv.Atoi(s) + onlineT[userID] = cur + 60 + } else if s[0] == 'A' { + lazy++ + } else if s[0] == 'H' { + for i := 0; i < numberOfUsers; i++ { + if onlineT[i] <= cur { + ans[i]++ + } + } + } else { + mentions := strings.Split(s, " ") + for _, m := range mentions { + userID, _ := strconv.Atoi(m[2:]) + ans[userID]++ + } + } + } + + if lazy > 0 { + for i := 0; i < numberOfUsers; i++ { + ans[i] += lazy + } + } + + return ans +} +``` +#### TypeScript + +```ts +function countMentions(numberOfUsers: number, events: string[][]): number[] { + events.sort((a, b) => { + const x = +a[1]; + const y = +b[1]; + if (x === y) { + return a[0].charAt(2) < b[0].charAt(2) ? -1 : 1; + } + return x - y; + }); + + const ans: number[] = Array(numberOfUsers).fill(0); + const onlineT: number[] = Array(numberOfUsers).fill(0); + let lazy = 0; + + for (const [etype, ts, s] of events) { + const cur = +ts; + if (etype.charAt(0) === 'O') { + const userID = +s; + onlineT[userID] = cur + 60; + } else if (s.charAt(0) === 'A') { + lazy++; + } else if (s.charAt(0) === 'H') { + for (let i = 0; i < numberOfUsers; i++) { + if (onlineT[i] <= cur) { + ans[i]++; + } + } + } else { + const mentions = s.split(' '); + for (const m of mentions) { + const userID = +m.slice(2); + ans[userID]++; + } + } + } + + if (lazy > 0) { + for (let i = 0; i < numberOfUsers; i++) { + ans[i] += lazy; + } + } + + return ans; +} ``` diff --git a/solution/3400-3499/3433.Count Mentions Per User/README_EN.md b/solution/3400-3499/3433.Count Mentions Per User/README_EN.md index b70efc2c749cc..7d159de5091c3 100644 --- a/solution/3400-3499/3433.Count Mentions Per User/README_EN.md +++ b/solution/3400-3499/3433.Count Mentions Per User/README_EN.md @@ -124,32 +124,252 @@ tags: -### Solution 1 +### Solution 1: Sorting + Simulation + +We sort the events in ascending order of timestamps. If the timestamps are the same, we place OFFLINE events before MESSAGE events. + +Then we simulate the occurrence of events, using the `online_t` array to record the next online time for each user and a variable `lazy` to record the number of mentions that need to be applied to all users. + +We traverse the event list and handle each event based on its type: + +- If it is an ONLINE event, we update the `online_t` array. +- If it is an ALL event, we increment `lazy` by one. +- If it is a HERE event, we traverse the `online_t` array. If a user's next online time is less than or equal to the current time, we increment that user's mention count by one. +- If it is a MESSAGE event, we increment the mention count of the mentioned user by one. + +Finally, if `lazy` is greater than 0, we add `lazy` to the mention count of all users. + +The time complexity is $O(n + m \times \log m \log M + L)$, and the space complexity is $O(n)$. Here, $n$ and $m$ are the total number of users and events, respectively, while $M$ and $L$ are the maximum value of the timestamps and the total length of all mentioned strings, respectively. #### Python3 ```python - +class Solution: + def countMentions(self, numberOfUsers: int, events: List[List[str]]) -> List[int]: + events.sort(key=lambda e: (int(e[1]), e[0][2])) + ans = [0] * numberOfUsers + online_t = [0] * numberOfUsers + lazy = 0 + for etype, ts, s in events: + cur = int(ts) + if etype[0] == "O": + online_t[int(s)] = cur + 60 + elif s[0] == "A": + lazy += 1 + elif s[0] == "H": + for i, t in enumerate(online_t): + if t <= cur: + ans[i] += 1 + else: + for a in s.split(): + ans[int(a[2:])] += 1 + if lazy: + for i in range(numberOfUsers): + ans[i] += lazy + return ans ``` #### Java ```java - +class Solution { + public int[] countMentions(int numberOfUsers, List> events) { + events.sort((a, b) -> { + int x = Integer.parseInt(a.get(1)); + int y = Integer.parseInt(b.get(1)); + if (x == y) { + return a.get(0).charAt(2) - b.get(0).charAt(2); + } + return x - y; + }); + int[] ans = new int[numberOfUsers]; + int[] onlineT = new int[numberOfUsers]; + int lazy = 0; + for (var e : events) { + String etype = e.get(0); + int cur = Integer.parseInt(e.get(1)); + String s = e.get(2); + if (etype.charAt(0) == 'O') { + onlineT[Integer.parseInt(s)] = cur + 60; + } else if (s.charAt(0) == 'A') { + ++lazy; + } else if (s.charAt(0) == 'H') { + for (int i = 0; i < numberOfUsers; ++i) { + if (onlineT[i] <= cur) { + ++ans[i]; + } + } + } else { + for (var a : s.split(" ")) { + ++ans[Integer.parseInt(a.substring(2))]; + } + } + } + if (lazy > 0) { + for (int i = 0; i < numberOfUsers; ++i) { + ans[i] += lazy; + } + } + return ans; + } +} ``` #### C++ ```cpp - +class Solution { +public: + vector countMentions(int numberOfUsers, vector>& events) { + ranges::sort(events, [](const vector& a, const vector& b) { + int x = stoi(a[1]); + int y = stoi(b[1]); + if (x == y) { + return a[0][2] < b[0][2]; + } + return x < y; + }); + + vector ans(numberOfUsers, 0); + vector onlineT(numberOfUsers, 0); + int lazy = 0; + + for (const auto& e : events) { + string etype = e[0]; + int cur = stoi(e[1]); + string s = e[2]; + + if (etype[0] == 'O') { + onlineT[stoi(s)] = cur + 60; + } else if (s[0] == 'A') { + lazy++; + } else if (s[0] == 'H') { + for (int i = 0; i < numberOfUsers; ++i) { + if (onlineT[i] <= cur) { + ++ans[i]; + } + } + } else { + stringstream ss(s); + string token; + while (ss >> token) { + ans[stoi(token.substr(2))]++; + } + } + } + + if (lazy > 0) { + for (int i = 0; i < numberOfUsers; ++i) { + ans[i] += lazy; + } + } + + return ans; + } +}; ``` #### Go ```go +func countMentions(numberOfUsers int, events [][]string) []int { + sort.Slice(events, func(i, j int) bool { + x, _ := strconv.Atoi(events[i][1]) + y, _ := strconv.Atoi(events[j][1]) + if x == y { + return events[i][0][2] < events[j][0][2] + } + return x < y + }) + + ans := make([]int, numberOfUsers) + onlineT := make([]int, numberOfUsers) + lazy := 0 + + for _, e := range events { + etype := e[0] + cur, _ := strconv.Atoi(e[1]) + s := e[2] + + if etype[0] == 'O' { + userID, _ := strconv.Atoi(s) + onlineT[userID] = cur + 60 + } else if s[0] == 'A' { + lazy++ + } else if s[0] == 'H' { + for i := 0; i < numberOfUsers; i++ { + if onlineT[i] <= cur { + ans[i]++ + } + } + } else { + mentions := strings.Split(s, " ") + for _, m := range mentions { + userID, _ := strconv.Atoi(m[2:]) + ans[userID]++ + } + } + } + + if lazy > 0 { + for i := 0; i < numberOfUsers; i++ { + ans[i] += lazy + } + } + + return ans +} +``` +#### TypeScript + +```ts +function countMentions(numberOfUsers: number, events: string[][]): number[] { + events.sort((a, b) => { + const x = +a[1]; + const y = +b[1]; + if (x === y) { + return a[0].charAt(2) < b[0].charAt(2) ? -1 : 1; + } + return x - y; + }); + + const ans: number[] = Array(numberOfUsers).fill(0); + const onlineT: number[] = Array(numberOfUsers).fill(0); + let lazy = 0; + + for (const [etype, ts, s] of events) { + const cur = +ts; + if (etype.charAt(0) === 'O') { + const userID = +s; + onlineT[userID] = cur + 60; + } else if (s.charAt(0) === 'A') { + lazy++; + } else if (s.charAt(0) === 'H') { + for (let i = 0; i < numberOfUsers; i++) { + if (onlineT[i] <= cur) { + ans[i]++; + } + } + } else { + const mentions = s.split(' '); + for (const m of mentions) { + const userID = +m.slice(2); + ans[userID]++; + } + } + } + + if (lazy > 0) { + for (let i = 0; i < numberOfUsers; i++) { + ans[i] += lazy; + } + } + + return ans; +} ``` diff --git a/solution/3400-3499/3433.Count Mentions Per User/Solution.cpp b/solution/3400-3499/3433.Count Mentions Per User/Solution.cpp new file mode 100644 index 0000000000000..153fff707ccb2 --- /dev/null +++ b/solution/3400-3499/3433.Count Mentions Per User/Solution.cpp @@ -0,0 +1,49 @@ +class Solution { +public: + vector countMentions(int numberOfUsers, vector>& events) { + ranges::sort(events, [](const vector& a, const vector& b) { + int x = stoi(a[1]); + int y = stoi(b[1]); + if (x == y) { + return a[0][2] < b[0][2]; + } + return x < y; + }); + + vector ans(numberOfUsers, 0); + vector onlineT(numberOfUsers, 0); + int lazy = 0; + + for (const auto& e : events) { + string etype = e[0]; + int cur = stoi(e[1]); + string s = e[2]; + + if (etype[0] == 'O') { + onlineT[stoi(s)] = cur + 60; + } else if (s[0] == 'A') { + lazy++; + } else if (s[0] == 'H') { + for (int i = 0; i < numberOfUsers; ++i) { + if (onlineT[i] <= cur) { + ++ans[i]; + } + } + } else { + stringstream ss(s); + string token; + while (ss >> token) { + ans[stoi(token.substr(2))]++; + } + } + } + + if (lazy > 0) { + for (int i = 0; i < numberOfUsers; ++i) { + ans[i] += lazy; + } + } + + return ans; + } +}; diff --git a/solution/3400-3499/3433.Count Mentions Per User/Solution.go b/solution/3400-3499/3433.Count Mentions Per User/Solution.go new file mode 100644 index 0000000000000..00ddbe2783e19 --- /dev/null +++ b/solution/3400-3499/3433.Count Mentions Per User/Solution.go @@ -0,0 +1,47 @@ +func countMentions(numberOfUsers int, events [][]string) []int { + sort.Slice(events, func(i, j int) bool { + x, _ := strconv.Atoi(events[i][1]) + y, _ := strconv.Atoi(events[j][1]) + if x == y { + return events[i][0][2] < events[j][0][2] + } + return x < y + }) + + ans := make([]int, numberOfUsers) + onlineT := make([]int, numberOfUsers) + lazy := 0 + + for _, e := range events { + etype := e[0] + cur, _ := strconv.Atoi(e[1]) + s := e[2] + + if etype[0] == 'O' { + userID, _ := strconv.Atoi(s) + onlineT[userID] = cur + 60 + } else if s[0] == 'A' { + lazy++ + } else if s[0] == 'H' { + for i := 0; i < numberOfUsers; i++ { + if onlineT[i] <= cur { + ans[i]++ + } + } + } else { + mentions := strings.Split(s, " ") + for _, m := range mentions { + userID, _ := strconv.Atoi(m[2:]) + ans[userID]++ + } + } + } + + if lazy > 0 { + for i := 0; i < numberOfUsers; i++ { + ans[i] += lazy + } + } + + return ans +} diff --git a/solution/3400-3499/3433.Count Mentions Per User/Solution.java b/solution/3400-3499/3433.Count Mentions Per User/Solution.java new file mode 100644 index 0000000000000..4e990b741016d --- /dev/null +++ b/solution/3400-3499/3433.Count Mentions Per User/Solution.java @@ -0,0 +1,41 @@ +class Solution { + public int[] countMentions(int numberOfUsers, List> events) { + events.sort((a, b) -> { + int x = Integer.parseInt(a.get(1)); + int y = Integer.parseInt(b.get(1)); + if (x == y) { + return a.get(0).charAt(2) - b.get(0).charAt(2); + } + return x - y; + }); + int[] ans = new int[numberOfUsers]; + int[] onlineT = new int[numberOfUsers]; + int lazy = 0; + for (var e : events) { + String etype = e.get(0); + int cur = Integer.parseInt(e.get(1)); + String s = e.get(2); + if (etype.charAt(0) == 'O') { + onlineT[Integer.parseInt(s)] = cur + 60; + } else if (s.charAt(0) == 'A') { + ++lazy; + } else if (s.charAt(0) == 'H') { + for (int i = 0; i < numberOfUsers; ++i) { + if (onlineT[i] <= cur) { + ++ans[i]; + } + } + } else { + for (var a : s.split(" ")) { + ++ans[Integer.parseInt(a.substring(2))]; + } + } + } + if (lazy > 0) { + for (int i = 0; i < numberOfUsers; ++i) { + ans[i] += lazy; + } + } + return ans; + } +} diff --git a/solution/3400-3499/3433.Count Mentions Per User/Solution.py b/solution/3400-3499/3433.Count Mentions Per User/Solution.py new file mode 100644 index 0000000000000..4f4e30126f009 --- /dev/null +++ b/solution/3400-3499/3433.Count Mentions Per User/Solution.py @@ -0,0 +1,23 @@ +class Solution: + def countMentions(self, numberOfUsers: int, events: List[List[str]]) -> List[int]: + events.sort(key=lambda e: (int(e[1]), e[0][2])) + ans = [0] * numberOfUsers + online_t = [0] * numberOfUsers + lazy = 0 + for etype, ts, s in events: + cur = int(ts) + if etype[0] == "O": + online_t[int(s)] = cur + 60 + elif s[0] == "A": + lazy += 1 + elif s[0] == "H": + for i, t in enumerate(online_t): + if t <= cur: + ans[i] += 1 + else: + for a in s.split(): + ans[int(a[2:])] += 1 + if lazy: + for i in range(numberOfUsers): + ans[i] += lazy + return ans diff --git a/solution/3400-3499/3433.Count Mentions Per User/Solution.ts b/solution/3400-3499/3433.Count Mentions Per User/Solution.ts new file mode 100644 index 0000000000000..ef1d70ca1951c --- /dev/null +++ b/solution/3400-3499/3433.Count Mentions Per User/Solution.ts @@ -0,0 +1,44 @@ +function countMentions(numberOfUsers: number, events: string[][]): number[] { + events.sort((a, b) => { + const x = +a[1]; + const y = +b[1]; + if (x === y) { + return a[0].charAt(2) < b[0].charAt(2) ? -1 : 1; + } + return x - y; + }); + + const ans: number[] = Array(numberOfUsers).fill(0); + const onlineT: number[] = Array(numberOfUsers).fill(0); + let lazy = 0; + + for (const [etype, ts, s] of events) { + const cur = +ts; + if (etype.charAt(0) === 'O') { + const userID = +s; + onlineT[userID] = cur + 60; + } else if (s.charAt(0) === 'A') { + lazy++; + } else if (s.charAt(0) === 'H') { + for (let i = 0; i < numberOfUsers; i++) { + if (onlineT[i] <= cur) { + ans[i]++; + } + } + } else { + const mentions = s.split(' '); + for (const m of mentions) { + const userID = +m.slice(2); + ans[userID]++; + } + } + } + + if (lazy > 0) { + for (let i = 0; i < numberOfUsers; i++) { + ans[i] += lazy; + } + } + + return ans; +}