|
| 1 | +--- |
| 2 | +title: 3433.统计用户被提及情况:(大)模拟 |
| 3 | +date: 2025-12-12 18:30:01 |
| 4 | +tags: [题解, LeetCode, 中等, 数组, 数学, 排序, 模拟] |
| 5 | +categories: [题解, LeetCode] |
| 6 | +--- |
| 7 | + |
| 8 | +# 【LetMeFly】3433.统计用户被提及情况:(大)模拟 |
| 9 | + |
| 10 | +力扣题目链接:[https://leetcode.cn/problems/count-mentions-per-user/](https://leetcode.cn/problems/count-mentions-per-user/) |
| 11 | + |
| 12 | +<p>给你一个整数 <code>numberOfUsers</code> 表示用户总数,另有一个大小为 <code>n x 3</code> 的数组 <code>events</code> 。</p> |
| 13 | + |
| 14 | +<p>每个 <code inline="">events[i]</code> 都属于下述两种类型之一:</p> |
| 15 | + |
| 16 | +<ol> |
| 17 | + <li><strong>消息事件(Message Event):</strong><code>["MESSAGE", "timestamp<sub>i</sub>", "mentions_string<sub>i</sub>"]</code> |
| 18 | + |
| 19 | + <ul> |
| 20 | + <li>事件表示在 <code>timestamp<sub>i</sub></code> 时,一组用户被消息提及。</li> |
| 21 | + <li><code>mentions_string<sub>i</sub></code> 字符串包含下述标识符之一: |
| 22 | + <ul> |
| 23 | + <li><code>id<number></code>:其中 <code><number></code> 是一个区间 <code>[0,numberOfUsers - 1]</code> 内的整数。可以用单个空格分隔 <strong>多个</strong> id ,并且 id 可能重复。此外,这种形式可以提及离线用户。</li> |
| 24 | + <li><code>ALL</code>:提及 <strong>所有</strong> 用户。</li> |
| 25 | + <li><code>HERE</code>:提及所有 <strong>在线</strong> 用户。</li> |
| 26 | + </ul> |
| 27 | + </li> |
| 28 | + </ul> |
| 29 | + </li> |
| 30 | + <li><strong>离线事件(Offline Event):</strong><code>["OFFLINE", "timestamp<sub>i</sub>", "id<sub>i</sub>"]</code> |
| 31 | + <ul> |
| 32 | + <li>事件表示用户 <code>id<sub>i</sub></code> 在 <code>timestamp<sub>i</sub></code> 时变为离线状态 <strong>60 个单位时间</strong>。用户会在 <code>timestamp<sub>i</sub> + 60</code> 时自动再次上线。</li> |
| 33 | + </ul> |
| 34 | + </li> |
| 35 | +</ol> |
| 36 | + |
| 37 | +<p>返回数组 <code>mentions</code> ,其中 <code>mentions[i]</code> 表示 id 为 <code>i</code> 的用户在所有 <code>MESSAGE</code> 事件中被提及的次数。</p> |
| 38 | + |
| 39 | +<p>最初所有用户都处于在线状态,并且如果某个用户离线或者重新上线,其对应的状态变更将会在所有相同时间发生的消息事件之前进行处理和同步。</p> |
| 40 | + |
| 41 | +<p><strong>注意 </strong>在单条消息中,同一个用户可能会被提及多次。每次提及都需要被 <strong>分别</strong> 统计。</p> |
| 42 | + |
| 43 | +<p> </p> |
| 44 | + |
| 45 | +<p><b>示例 1:</b></p> |
| 46 | + |
| 47 | +<div class="example-block"> |
| 48 | +<p><span class="example-io"><b>输入:</b>numberOfUsers = 2, events = [["MESSAGE","10","id1 id0"],["OFFLINE","11","0"],["MESSAGE","71","HERE"]]</span></p> |
| 49 | + |
| 50 | +<p><span class="example-io"><b>输出:</b>[2,2]</span></p> |
| 51 | + |
| 52 | +<p><b>解释:</b></p> |
| 53 | + |
| 54 | +<p>最初,所有用户都在线。</p> |
| 55 | + |
| 56 | +<p>时间戳 10 ,<code>id1</code> 和 <code>id0</code> 被提及,<code>mentions = [1,1]</code></p> |
| 57 | + |
| 58 | +<p>时间戳 11 ,<code>id0</code> <strong>离线</strong> 。</p> |
| 59 | + |
| 60 | +<p>时间戳 71 ,<code>id0</code> 再次 <strong>上线</strong> 并且 <code>"HERE"</code> 被提及,<code>mentions = [2,2]</code></p> |
| 61 | +</div> |
| 62 | + |
| 63 | +<p><b>示例 2:</b></p> |
| 64 | + |
| 65 | +<div class="example-block"> |
| 66 | +<p><span class="example-io"><b>输入:</b>numberOfUsers = 2, events = [["MESSAGE","10","id1 id0"],["OFFLINE","11","0"],["MESSAGE","12","ALL"]]</span></p> |
| 67 | + |
| 68 | +<p><span class="example-io"><b>输出:</b>[2,2]</span></p> |
| 69 | + |
| 70 | +<p><b>解释:</b></p> |
| 71 | + |
| 72 | +<p>最初,所有用户都在线。</p> |
| 73 | + |
| 74 | +<p>时间戳 10 ,<code>id1</code> 和 <code>id0</code> 被提及,<code>mentions = [1,1]</code></p> |
| 75 | + |
| 76 | +<p>时间戳 11 ,<code>id0</code> <strong>离线</strong> 。</p> |
| 77 | + |
| 78 | +<p>时间戳 12 ,<code>"ALL"</code> 被提及。这种方式将会包括所有离线用户,所以 <code>id0</code> 和 <code>id1</code> 都被提及,<code>mentions = [2,2]</code></p> |
| 79 | +</div> |
| 80 | + |
| 81 | +<p><b>示例 3:</b></p> |
| 82 | + |
| 83 | +<div class="example-block"> |
| 84 | +<p><span class="example-io"><b>输入:</b>numberOfUsers = 2, events = [["OFFLINE","10","0"],["MESSAGE","12","HERE"]]</span></p> |
| 85 | + |
| 86 | +<p><span class="example-io"><b>输出:</b>[0,1]</span></p> |
| 87 | + |
| 88 | +<p><b>解释:</b></p> |
| 89 | + |
| 90 | +<p>最初,所有用户都在线。</p> |
| 91 | + |
| 92 | +<p>时间戳 10 ,<code>id0</code> <strong>离线</strong> <b>。</b></p> |
| 93 | + |
| 94 | +<p>时间戳 12 ,<code>"HERE"</code> 被提及。由于 <code>id0</code> 仍处于离线状态,其将不会被提及,<code>mentions = [0,1]</code></p> |
| 95 | +</div> |
| 96 | + |
| 97 | +<p> </p> |
| 98 | + |
| 99 | +<p><b>提示:</b></p> |
| 100 | + |
| 101 | +<ul> |
| 102 | + <li><code>1 <= numberOfUsers <= 100</code></li> |
| 103 | + <li><code>1 <= events.length <= 100</code></li> |
| 104 | + <li><code>events[i].length == 3</code></li> |
| 105 | + <li><code>events[i][0]</code> 的值为 <code>MESSAGE</code> 或 <code>OFFLINE</code> 。</li> |
| 106 | + <li><code>1 <= int(events[i][1]) <= 10<sup>5</sup></code></li> |
| 107 | + <li>在任意 <code>"MESSAGE"</code> 事件中,以 <code>id<number></code> 形式提及的用户数目介于 <code>1</code> 和 <code>100</code> 之间。</li> |
| 108 | + <li><code>0 <= <number> <= numberOfUsers - 1</code></li> |
| 109 | + <li>题目保证 <code>OFFLINE</code> 引用的用户 id 在事件发生时处于 <strong>在线</strong> 状态。</li> |
| 110 | +</ul> |
| 111 | + |
| 112 | + |
| 113 | + |
| 114 | +## 解题方法:模拟 |
| 115 | + |
| 116 | +最多100个人,最多100个事件,所以直接暴力模拟就好了。 |
| 117 | + |
| 118 | +创建一个答案数组,初始值全部为0,接着开始遍历事件: |
| 119 | + |
| 120 | +* 如果事件是`OFFLINE`,则什么都不做,直接continue。否则一定是消息事件: |
| 121 | +* 如果事件是`ALL`,则每人+1 |
| 122 | +* 如果事件是`HERE`,则先每人+1,然后再遍历一遍事件数组,如果存在60时间内的下线时间,则此人-1 |
| 123 | +* 否则(@指定人),被提及到的人们+1 |
| 124 | + |
| 125 | +以上。 |
| 126 | + |
| 127 | +### 时空复杂度分析 |
| 128 | + |
| 129 | +令$e=len(events)$,$n=numberOfUsers$: |
| 130 | + |
| 131 | ++ 单次操作时间复杂度:下线$O(1)$、所有人$O(n)$、在线人$O(n+e)$、指定人$O(len(events[i][2]))$ |
| 132 | ++ 总空间复杂度$O(n)$ |
| 133 | + |
| 134 | +### AC代码 |
| 135 | + |
| 136 | +#### Python |
| 137 | + |
| 138 | +```python |
| 139 | +''' |
| 140 | +LastEditTime: 2025-12-12 13:42:16 |
| 141 | +''' |
| 142 | +from typing import List |
| 143 | + |
| 144 | +class Solution: |
| 145 | + def countMentions(self, numberOfUsers: int, events: List[List[str]]) -> List[int]: |
| 146 | + ans: List[int] = [0] * numberOfUsers |
| 147 | + for action, time, who in events: |
| 148 | + if action == "OFFLINE": |
| 149 | + continue |
| 150 | + if who == "ALL": |
| 151 | + ans = [x + 1 for x in ans] |
| 152 | + elif who == "HERE": |
| 153 | + ans = [x + 1 for x in ans] |
| 154 | + for a, t, w in events: |
| 155 | + if a == "OFFLINE" and int(time) - 60 < int(t) <= int(time): |
| 156 | + ans[int(w)] -= 1 |
| 157 | + else: |
| 158 | + for i in (int(w[2:]) for w in who.split(" ")): |
| 159 | + ans[i] += 1 |
| 160 | + return ans # 差点忘了return |
| 161 | +``` |
| 162 | + |
| 163 | +> 同步发文于[CSDN](https://letmefly.blog.csdn.net/article/details/155861707)和我的[个人博客](https://blog.letmefly.xyz/),原创不易,转载经作者同意后请附上[原文链接](https://blog.letmefly.xyz/2025/12/12/LeetCode%203433.%E7%BB%9F%E8%AE%A1%E7%94%A8%E6%88%B7%E8%A2%AB%E6%8F%90%E5%8F%8A%E6%83%85%E5%86%B5/)哦~ |
| 164 | +> |
| 165 | +> 千篇源码题解[已开源](https://github.com/LetMeFly666/LeetCode) |
0 commit comments