Huawei OD コンピュータベースのテストアルゴリズムの質問: スパム阻止

目次

質問部分

解釈と分析

コード


質問部分

トピック スパムブロック
困難 災害
質問の説明 一般の人々はスパム テキスト メッセージを嫌っており、スパム テキスト メッセージの送信者を特定することを望んでおり、この目的のために、多くのソフトウェアにスパム テキスト メッセージ識別メカニズムが追加されています。分析の結果、通常のユーザーのテキスト メッセージは対話型であることが多いのに対し、スパム テキスト メッセージは多数の一方通行のテキスト メッセージであることがわかり、スパム テキスト メッセージは次のルールに従って識別されます。次の条件のいずれかを満たしている場合、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);
}

(完)

おすすめ

転載: blog.csdn.net/ZiJinShi/article/details/133040634
おすすめ