力扣--3433. 统计用户被提及情况

前言:

这是力扣第3433的一道中等算法题,废话不多说,看题目和代码!


题目:

给你一个整数 numberOfUsers 表示用户总数,另有一个大小为 n x 3 的数组 events

每个 events[i] 都属于下述两种类型之一:

  1. 消息事件(Message Event):["MESSAGE", "timestampi", "mentions_stringi"]

    • 事件表示在 timestampi 时,一组用户被消息提及。

    • mentions_stringi 字符串包含下述标识符之一:

      • id<number>:其中 <number> 是一个区间 [0,numberOfUsers - 1] 内的整数。可以用单个空格分隔 多个 id ,并且 id 可能重复。此外,这种形式可以提及离线用户。

      • ALL:提及 所有 用户。

      • HERE:提及所有 在线 用户。

  2. 离线事件(Offline Event):["OFFLINE", "timestampi", "idi"]

    • 事件表示用户 iditimestampi 时变为离线状态 60 个单位时间。用户会在 timestampi + 60 时自动再次上线。

返回数组 mentions ,其中 mentions[i] 表示 id 为 i 的用户在所有 MESSAGE 事件中被提及的次数。

最初所有用户都处于在线状态,并且如果某个用户离线或者重新上线,其对应的状态变更将会在所有相同时间发生的消息事件之前进行处理和同步。

注意 在单条消息中,同一个用户可能会被提及多次。每次提及都需要被 分别 统计。

示例 1:

输入:numberOfUsers = 2, events = \["MESSAGE","10","id1 id0","OFFLINE","11","0","MESSAGE","71","HERE"]

输出:2,2

解释:

最初,所有用户都在线。

时间戳 10 ,id1id0 被提及,mentions = [1,1]

时间戳 11 ,id0 离线 。

时间戳 71 ,id0 再次 上线 并且 "HERE" 被提及,mentions = [2,2]

示例 2:

输入:numberOfUsers = 2, events = \["MESSAGE","10","id1 id0","OFFLINE","11","0","MESSAGE","12","ALL"]

输出:2,2

解释:

最初,所有用户都在线。

时间戳 10 ,id1id0 被提及,mentions = [1,1]

时间戳 11 ,id0 离线 。

时间戳 12 ,"ALL" 被提及。这种方式将会包括所有离线用户,所以 id0id1 都被提及,mentions = [2,2]

示例 3:

输入:numberOfUsers = 2, events = \["OFFLINE","10","0","MESSAGE","12","HERE"]

输出:0,1

解释:

最初,所有用户都在线。

时间戳 10 ,id0 离线 。

时间戳 12 ,"HERE" 被提及。由于 id0 仍处于离线状态,其将不会被提及,mentions = [0,1]

提示:

  • 1 <= numberOfUsers <= 100

  • 1 <= events.length <= 100

  • events[i].length == 3

  • events[i][0] 的值为 MESSAGEOFFLINE

  • 1 <= int(events[i][1]) <= 105

  • 在任意 "MESSAGE" 事件中,以 id<number> 形式提及的用户数目介于 1100 之间。

  • 0 <= <number> <= numberOfUsers - 1

  • 题目保证 OFFLINE 引用的用户 id 在事件发生时处于 在线 状态。


题目分析:

这个题目就是一个计算用户被@的次数,简单理解

ALL:@所有人

HERE:@在线人员

所有就可以理解成:

对于 ALL ,用一个变量统计所有用户被提及的次数,看到ALL就所有人加1。

对于 HERE 消息:

1、先认为所有用户都被提及了,把如同ALL,加1。

2、此刻离线的用户不能被计入,需要把这些用户的提及次数减1。

比如一个用户在 5 时刻离线,在 65 时刻在线,那么发生在 5,64 中的 HERE 消息个数,就是需要减去的提及次数。

借鉴 前缀和 的思想,用 0,64 中的 HERE 消息个数,减去 0,4 中的 HERE 消息个数,即为 5,64 中的 HERE 消息个数。

把离线事件、上线事件、HERE 消息混在一起,按照发生时间排序。相同时间的,HERE 消息排在后面。然后遍历这些事件,同时统计 HERE 消息个数 here。离线时加上 here,在线时减去 here。这样一加一减,最终减去的就是离线时的 HERE 消息个数。


代码:

class Solution {

public int\[\] countMentions(int numberOfUsers, List<List<String>> events) {

int\[\] ans = new intnumberOfUsers;

List<int\[\]> es = new ArrayList<>(); // (timestamp, type, id)

int all = 0;

for (List<String> e : events) {

int curT = Integer.parseInt(e.get(1)); // 当前时间

String mention = e.get(2);

if (e.get(0).charAt(0) == 'O') { // 离线

int i = Integer.parseInt(mention);

es.add(new int\[\]{curT, 1, i});

es.add(new int\[\]{curT + 60, -1, i});

} else if (mention.charAt(0) == 'A') { // @所有人

all++;

} else if (mention.charAt(0) == 'H') { // @所有在线用户

all++;

es.add(new int\[\]{curT, 2, -1});

} else { // @id

for (String s : mention.split(" ")) {

int i = Integer.parseInt(s.substring(2));

ansi++;

}

}

}

es.sort((a, b) -> a0 != b0 ? a0 - b0 : a1 - b1);

int here = 0;

for (int\[\] e : es) {

int type = e1;

if (type == 2) {

here++;

} else {

// 注意 HERE 排在后面,还没有计入发生在此刻的 HERE 消息

anse\[2] += type * here; // type=1 是加,-1 是减

}

}

for (int i = 0; i < numberOfUsers; i++) {

ansi += all;

}

return ans;

}

}


代码分析:

1、初始化

一个ans数组用于统计每个用户被提交(艾特@)的次数

一个es列表用于存events中每个事件

一个all变量统计存放被@次数(提交次数)

int\[\] ans = new intnumberOfUsers;

List<int\[\]> es = new ArrayList<>(); // (timestamp, type, id)

int all = 0;

2、逻辑实现

events = \["MESSAGE","10","id1 id0","OFFLINE","11","0","MESSAGE","71","HERE"]

events是一个列表含列表,在列表里面是字符串

先获取每个事件的时间戳和id

id这里看题要求,有三个可能

mentions_stringi 字符串包含下述标识符之一:

  • id<number>:其中 <number> 是一个区间 [0,numberOfUsers - 1] 内的整数。可以用单个空格分隔 多个 id ,并且 id 可能重复。此外,这种形式可以提及离线用户。
  • ALL:提及 所有 用户。
  • HERE:提及所有 在线 用户。

然后all是所有人加1,here也是先所有人加1,后面删减不符合的

同时离线和离线在上线都需要加入到数组es,为后续计算here

最后还需要注意一下案例一那种情况!

for (List<String> e : events) {

int curT = Integer.parseInt(e.get(1)); // 当前时间

String mention = e.get(2);

if (e.get(0).charAt(0) == 'O') { // 离线

int i = Integer.parseInt(mention);

es.add(new int\[\]{curT, 1, i});//离线。type = 1

es.add(new int\[\]{curT + 60, -1, i});//重新上线 type = -1

} else if (mention.charAt(0) == 'A') { // @所有人

all++;

} else if (mention.charAt(0) == 'H') { // @所有在线用户

all++;

es.add(new int\[\]{curT, 2, -1});//here type = 2

} else { // @id

for (String s : mention.split(" ")) {

int i = Integer.parseInt(s.substring(2));

ansi++;

}

}

}

3、排序

对es数组进行排序,每个列表的第一个是时间戳,按时间戳升序排序,如果时间相等,先是type = -1 即重新上线的,在type = 1 即离线 ,最后再是type = 2 即here,也是升序

es.sort((a, b) -> a0 != b0 ? a0 - b0 : a1 - b1);

4、计算here

这里就是扣除here,因为统计here个数,离线是1是先记着,一旦上线变成-1,就扣除之前统计的here

int here = 0;

for (int\[\] e : es) {

int type = e1;

if (type == 2) {

here++;

} else {

// 注意 HERE 排在后面,还没有计入发生在此刻的 HERE 消息

anse\[2] += type * here; // type=1 是加,-1 是减

}

}

5、每个用户加上all的次数

按题目分析的,每个用户都加all

for (int i = 0; i < numberOfUsers; i++) {

ansi += all;

}


结语:

这道题是力扣算法,可以参考 灵神 的思路和解法!加油!

相关推荐
ZJH__GO16 小时前
java项目-流水线线程池
java·开发语言
●VON16 小时前
鸿蒙NEXT ArkUI进阶:用CustomBuilder打造高定制化品牌页签栏
java·华为·harmonyos·鸿蒙·新特性
vortex516 小时前
国密(商用密码)算法核心参数速查
算法·密码学
夕除16 小时前
spring boot 16
java·spring boot·后端
努力成为AK大王16 小时前
Spring Bean 作用域与生命周期
java·后端·spring
希望永不加班16 小时前
SpringBoot 消息幂等性设计:防重复消费
java·开发语言·spring boot·后端·spring
我是一颗柠檬16 小时前
【JDK8新特性】CompletableFuture异步编程Day10
java·开发语言·后端·intellij-idea
a231212116 小时前
从零搭建Spring Ai多智能体后端应用
java·运维·微服务·多智能体·后端开发·spring ai
Yeats_Liao16 小时前
5:Servlet程序-Java Web
java·后端·设计
小马爱打代码16 小时前
Spring源码 第八篇:Spring 5 源码深度拆解 - Spring 资源加载与 Environment 环境体系
java·后端·spring