Coding Test/Programmers

[Lv.1] 신고 결과 받기 [프로그래머스_코딩테스트] [해시, 구현] [40분] [2022 KAKAO BLIND RECRUITMENT]

whawoo 2025. 6. 16. 17:53
반응형

🔍 문제 요약

https://school.programmers.co.kr/learn/courses/30/lessons/92334

 

프로그래머스

SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프

programmers.co.kr

id_list와 신고자 id와 피신고자 id 목록이 들어있는 report가 주어지고 신고를 당한 횟수가 k 이상인 경우 정지가 된 다고 할 때 각 id_list id들이 신고해서 정지가 된 계정의 개수를 반환하는 문제

🧠 나의 접근 방식과 시행착오

21분 정도 걸린 문제. 문제가 길긴 길지만 핵심 자체는 어렵지 않은 문제라서 일단 풀긴 풀었다. 다만 이 부분도 최적화적으로 고려할 부분이 있는 문항에 변수 이름도 좀 고쳤으면 싶었다. Dictionary에 신고자 : 피신고자 리스트로 하나, 피신고자 : 신고당한 횟수로 하나를 만들어서 풀었다.

using System;
using System.Collections.Generic;

public class Solution
{
    /// <summary>
    /// 신고 결과 받기
    /// https://school.programmers.co.kr/learn/courses/30/lessons/92334
    /// </summary>
    public int[] solution(string[] id_list, string[] report, int k)
    {
        // 신고자 : 피신고자 리스트
        Dictionary<string, List<string>> singoDict = new Dictionary<string, List<string>>();
        // 피신고자 : 신고당한 횟수
        Dictionary<string, int> countDict = new Dictionary<string, int>();

        foreach (var data in report)
        {
            var datas = data.Split(' ');
            var idStr = datas[0];
            var singoId = datas[1];
            bool alreadySingo = false;
            
            if (singoDict.ContainsKey(idStr) && singoDict[idStr] != null)
            {
                if (!singoDict[idStr].Contains(singoId))
                {
                    singoDict[idStr].Add(singoId);
                }
                else
                {
                    alreadySingo = true;
                }
            }
            else if (!singoDict.ContainsKey(idStr))
            {
                singoDict.Add(idStr, new List<string>());
                singoDict[idStr].Add(singoId);
            }

            if (alreadySingo)
            {
                continue;
            }

            if (!countDict.ContainsKey(singoId))
            {
                countDict.Add(singoId, 1);
            }
            else
            {
                countDict[singoId]++;
            }
        }
        
        int[] answer = new int[id_list.Length];

        for (int i = 0; i < id_list.Length; i++)
        {
            var id = id_list[i];
            int count = 0;
            
            if (singoDict.ContainsKey(id))
            {
                var singoList = singoDict[id];

                if (singoList != null)
                {
                    foreach (var idStr in singoList)
                    {
                        if (countDict[idStr] >= k)
                        {
                            count++;
                        }
                    }
                }
            }

            answer[i] = count;
        }
        
        return answer;
    }
}

/// <summary>
/// C# 7.3
/// </summary>
internal class Program
{
    public static void Main(string[] args)
    {
        var sl = new Solution();
        var id_list1 = new[] { "muzi", "frodo", "apeach", "neo" };
        var report1 = new[] { "muzi frodo", "apeach frodo", "frodo neo", "muzi neo", "apeach muzi" };
        int k1 = 2;
        var id_list2 = new[] { "con", "ryan" };
        var report2 = new[] { "ryan con", "ryan con", "ryan con", "ryan con" };
        int k2 = 3;
        var res1 = sl.solution(id_list1, report1, k1);
        var res2 = sl.solution(id_list2, report2, k2);

        foreach (var item in res1)
        {
            Console.Write(item + ", ");
        }
        Console.WriteLine();
        foreach (var item in res2)
        {
            Console.Write(item + ", ");
        }
    }
}

✅ 풀이 코드

막상 피드백을 받은 코드를 보니 정말 필자가 풀었던 것보다 로직적으로 깔끔하고 알아보기도 쉽게 되어있다는 것을 알았다. 일단 중요한 부분은 reportMap이 있고 신고자와 피신고자 목록이 HashSet으로 Value가 구현되어 있는 점. Add를 했을 때 HashSet의 경우 한 개만 존재하기 때문에 false 처리 된다는 점. 그렇게 해서 true인 경우에서만 reportCount (피신고자 : 횟수)를 증가시키는 점. 이 부분 반복문지 정말 깔끔하게 처리되어 있는 점을 알 수 있다. 늘 HashSet을 익숙해져야지 싶은데 잊어먹고 그냥 List로 해서 최적화를 놓치는 부분들이 많았던 듯 하다. 실제 개발에서도 HashSet은 유용하게 쓸 수 있을 것이라 생각하는 거라 잘 고민해보자

public int[] solution(string[] id_list, string[] report, int k)
{
    var reportMap = new Dictionary<string, HashSet<string>>();
    var reportCount = new Dictionary<string, int>();

    foreach (var id in id_list)
    {
        reportMap[id] = new HashSet<string>();
        reportCount[id] = 0;
    }

    // 유저별 신고 처리
    foreach (var r in report)
    {
        var parts = r.Split(' ');
        var reporter = parts[0];
        var target = parts[1];

        if (reportMap[reporter].Add(target))
        {
            reportCount[target]++;
        }
    }

    // 메일 발송 횟수 계산
    var answer = new int[id_list.Length];

    for (int i = 0; i < id_list.Length; i++)
    {
        var reporter = id_list[i];
        foreach (var reported in reportMap[reporter])
        {
            if (reportCount[reported] >= k)
            {
                answer[i]++;
            }
        }
    }

    return answer;
}

🔄 정리

HashSet을 사용해서 깔끔하게 풀 수 있는 문제라서 그냥 Dictionary<string, List<string>> 보다 Dictionary<string, HashSet<string>>을 써볼 수 있으면 좋겠다.

반응형