目次
質問部分
トピック | スパムブロック |
困難 | 災害 |
質問の説明 | 一般の人々はスパム テキスト メッセージを嫌っており、スパム テキスト メッセージの送信者を特定することを望んでおり、この目的のために、多くのソフトウェアにスパム テキスト メッセージ識別メカニズムが追加されています。分析の結果、通常のユーザーのテキスト メッセージは対話型であることが多いのに対し、スパム テキスト メッセージは多数の一方通行のテキスト メッセージであることがわかり、スパム テキスト メッセージは次のルールに従って識別されます。次の条件のいずれかを満たしている場合、A は スパム テキスト メッセージの送信者とみなされます: · A が送信したテキスト メッセージの受信者の中で、A にテキスト メッセージを送信していない人の数は L > 5 です。 ·テキスト メッセージの 数 A によって送信された - A によって受信されたテキスト メッセージの数 M > 10; · X が存在する場合、A はそれを X のテキスト メッセージの数 - A X が受信したテキスト メッセージの数 N > 5 に送信します。 |
説明を入力してください | 最初の行はエントリの数、次の数行は特定のエントリ、各エントリは ID のペア、最初の数字は送信者 ID、次の数字は受信者 ID で、スペースで区切られています。すべての ID は符号なし整数、最大 ID 値は 100 です。 同じエントリ内で 2 つの ID は同じではありません (つまり、自分自身にメッセージを送信しません)。 最後の行は指定された ID です。 |
出力の説明 | IDがスパムメッセージの送信者であるかどうかを出力(そうであればtrue、そうでない場合はfalseを出力)し、LとMの値を順に出力します(Nの値は一意ではないため、確認する必要はありません)出力します); 出力はすべて文字列です 。 |
追加情報 | なし |
-------------------------------------------------- ---- | |
例 | |
例1 | |
入力 | 15 1 2 1 3 1 4 1 5 1 6 1 7 1 8 1 9 1 10 1 11 1 12 1 13 1 14 14 1 1 15 1 |
出力 | 本当 13 13 |
説明する | true は 1 がスパマーであることを意味します。2 つの 13 は、送信者 1 の対応する L 値と M 値が両方とも 13 であることを表します。true 13 13 はスペースで区切ります。 注: true は文字列出力です。 |
例 2 | |
入力 | 15 1 2 1 3 1 4 1 5 1 6 1 7 1 8 1 9 1 10 1 11 1 12 1 13 1 14 14 1 1 15 2 |
出力 | 偽 0 -1 |
説明する | なし |
解釈と分析
質問の解釈:
質問で要求される 3 つのルールに従ってユーザーを判断します。3 つのルールのいずれかが満たされる場合、そのユーザーはスパム SMS 送信者になります。
分析とアイデア:
SMS 送信情報を 1 行ずつ読み取り、各行を文字列として配列入力に格納します。
最後の行を読み、確認したいIDを読み取ってidAに設定します。
申明如下变量:
1. receivers,一个集合,记录 idA 这个短信发送者发送短信的所有接收者 id。
2. senders, 一个集合,记录所有给 idA 发送短信的用户 id。
3. aSendCnt,整型数字,初始值为 0。记录 idA 发送的短信条数。
4. aReceiveCnt,整型数字,初始值为 0。记录 idA 接收的短信条数。
5. msgSendCntMap,一个 map,记录 idA 发送给其他用户,和其他用户发送给 idA 的短信条数。其中 key 的格式为 idA + " " +“其他用户id” (代表 idA 给其他用户发短信), 或 “其他用户id” + " " + idA(代表其他用户给 idA 发短信),值为整型数字,表示短信条数。
实现方法如下:
1. 遍历 inputs,对于 inputs中的每条字符串,设为 inputEle,以空格(" ")分隔,把它分成一个数组 inputEleSplits,其中 inputEleSplits[0] 为 空格前的 id,即短信发送者的 id;inputEleSplits[1] 为短信接收者的 id。对 inputEle 和 inputEleSplits 进行如下判断:
① 如果 inputEleSplits[0] 和 inputsEleSplits[1] 都不等于 idA,那么忽略这条信息(即不做任何处理)。
② 如果 inputEleSplits[0] 等于 idA,那么把 inputEleSplits[1] 加到 receivers 中去,并把 aSendCnt 加 1。与此同时,获取 msgSendCntMap.get( inputEle ) 的值,如果值为空,则赋值为 1;若不为空,则把其值加 1。
③ 如果 inputEleSplits[1] 等于 idA,那么把 inputEleSplits[0] 加到 senders 中去,并把 aReceiveCnt 加 1。与此同时,获取 msgSendCntMap.get( inputEle ) 的值,如果值为空,则赋值为 1;若不为空,则把其值加 1。
2. 遍历完 inputs 后,receivers、senders、aSendCnt、aReceiveCnt、msgSendCntMap均已初始化完毕。下一步,进行入操作:
① 申请变量 recSendCnt,初始值为 0。用以记录既给 idA 发过信息,也收到过 idA 的信息的用户数。遍历 senders 的每个元素,如果元素在 receivers 中,则 recSendCnt 加 1。遍历完后,集合receviers 的元素个数与 recSendCnt 的差,即为 L 的值。
② 用 aSendCnt 减去 aReceiveCnt,即为 M 的值。
③ 先假设第三条规则不存在这样的用户,申明变量布尔变量 exsitsX ,并赋值为 false。遍历 receivers,设每个元素为 tmpReceiver,分别求 msgSendCntMap.get( idA + " " + tmpReceiver ) 和 msgSendCntMap.get( tmpReceiver + " " + idA ) 的值,如果为空,则赋值为 0。求前者减去后者的差值,如果差值大于 5,则 existsX 赋值为 true,退出遍历;否则继续遍历下一个 tmpReceiver。
④ 如果 L > 5 或 M > 5 或 existsX == true,则此用户为垃圾短信发送者。
最后,输出对应的值。
此题时间复杂度 O(n),空间复杂度 O(n)。
代码实现
Java代码
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Scanner;
import java.util.Set;
/**
* 垃圾信息拦截
* @since 2023.09.20
* @version 0.1
* @author Frank
*
*/
public class MsgSpam {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while (sc.hasNext()) {
String input = sc.nextLine();
int count = Integer.parseInt( input );
String[] inputs = new String[count];
for( int i = 0; i < count; i ++ )
{
input = sc.nextLine();
inputs[i] = input;
}
String idA = sc.nextLine();
processMsgSpam( idA, inputs );
}
}
private static void processMsgSpam( String idA, String inputs[] )
{
Set<String> receivers = new HashSet<String>();
Set<String> senders = new HashSet<String>();
int aSendCnt = 0;
int aReceiveCnt = 0;
Map<String, Integer> msgSendCntMap = new HashMap<String, Integer>();
for( int i = 0; i < inputs.length; i ++ )
{
String inputEle = inputs[i];
String[] inputEleSplits = inputEle.split( " " );
if( ( !inputEleSplits[0].equals( idA ) ) && ( !inputEleSplits[1].equals( idA ) ) )
{
continue;
}
if( inputEleSplits[0].equals( idA ) )
{
receivers.add( inputEleSplits[1] );
aSendCnt += 1;
}else // inputEleSplits[1].equals( idA )
{
senders.add( inputEleSplits[0] );
aReceiveCnt += 1;
}
Integer tmpCnt = msgSendCntMap.get( inputEle );
if( tmpCnt == null )
{
tmpCnt = 0;
}
tmpCnt += 1;
msgSendCntMap.put( inputEle, tmpCnt );
}
int recSendCnt = 0;
for( Iterator<String> iter = senders.iterator(); iter.hasNext(); )
{
String tmpSender = iter.next();
if( receivers.contains( tmpSender ) )
{
recSendCnt ++;
}
}
int L = receivers.size() - recSendCnt;
int M = aSendCnt - aReceiveCnt;
boolean existsX = false;
for( Iterator<String> iter = receivers.iterator(); iter.hasNext(); )
{
String tmpReceiver = iter.next();
Integer tmpSendCnt = msgSendCntMap.get( idA + " " + tmpReceiver );
if( tmpSendCnt == null )
{
// will never come here
continue;
}
Integer tmpReceiveCnt = msgSendCntMap.get( tmpReceiver + " " + idA );
if( tmpReceiveCnt == null )
{
tmpReceiveCnt = 0;
}
if( tmpSendCnt - tmpReceiveCnt > 5 )
{
existsX = true;
break;
}
}
boolean isSpamSender = ( L > 5 ) || ( M > 5) || existsX;
System.out.println( isSpamSender + " " + L + " " + M );
}
}
JavaScript代码
const rl = require("readline").createInterface({ input: process.stdin });
var iter = rl[Symbol.asyncIterator]();
const readline = async () => (await iter.next()).value;
void async function() {
while (line = await readline()) {
var count = parseInt(line);
var inputs = new Array();
for (var i = 0; i < count; i++) {
inputs[i] = await readline();
}
var idA = await readline();
processMsgSpam(idA, inputs);
}
}();
function processMsgSpam(idA, inputs) {
var receivers = new Set();
var senders = new Set();
var aSendCnt = 0;
var aReceiveCnt = 0;
var msgSendCntMap = new Map();
for (var i = 0; i < inputs.length; i++) {
var inputEle = inputs[i];
var inputEleSplits = inputEle.split(" ");
if ((inputEleSplits[0] != idA) && (inputEleSplits[1] != idA)) {
continue;
}
if (inputEleSplits[0] == idA) {
receivers.add(inputEleSplits[1]);
aSendCnt += 1;
} else // inputEleSplits[1].equals( idA )
{
senders.add(inputEleSplits[0]);
aReceiveCnt += 1;
}
var tmpCnt = msgSendCntMap.get(inputEle);
if (tmpCnt == null) {
tmpCnt = 0;
}
tmpCnt += 1;
msgSendCntMap.set(inputEle, tmpCnt);
}
var recSendCnt = 0;
for (const item of senders) {
if (receivers.has(item)) {
recSendCnt++;
}
}
var L = receivers.size - recSendCnt;
var M = aSendCnt - aReceiveCnt;
var existsX = false;
for (const item of receivers) {
var tmpSendCnt = msgSendCntMap.get(idA + " " + item);
if (tmpSendCnt == null) {
// will never come here
continue;
}
var tmpReceiveCnt = msgSendCntMap.get(item + " " + idA);
if (tmpReceiveCnt == null) {
tmpReceiveCnt = 0;
}
if (tmpSendCnt - tmpReceiveCnt > 5) {
existsX = true;
break;
}
}
var isSpamSender = (L > 5) || (M > 5) || existsX;
console.log(isSpamSender + " " + L + " " + M);
}
(完)