본문 바로가기
프로그래밍/알고리즘 문제풀이

[pg] 프로그래머스 신고 결과 받기

by 노잼인간이라불립니다 2023. 7. 27.

0. 개요

 이 문제는 이전에 자료구조 지식과 알고리즘 지식이 없다시피 하던 시절 무작정 도전해서 풀어봤던 문제다. 그때에는 맵을 무려 3개나 사용해서 간신히 간신히 풀었던 기억이 있는데, 이번에 코테를 준비하면서 다시 한번 풀어보게 되었다.

 나도 쥐똥만큼은 성장한 것인지, 문제를 보고 얼마 지나지 않아 해결방법이 떠올랐다. Person이라는 객체를 만들어서 해결하면 좋겠다고 생각하고, 코딩을 시작했다.

 

1. 문제 정의

 이 문제는 유저들의 유저ID가 있고, 그 유저가 다른 유저를 신고했을 경우 신고당한 유저의 신고횟수가 증가하여(여러번 신고할시에는 1번만 신고한 것으로 간주된다.), 신고횟수가 최종적으로 메서드에 k라는 매개변수로 주어지는 값과 같거나 더 크면 그 유저를 신고한 유저들에게 결과 메일이 발송되는데, 유저별로 결과메일을 받은 횟수를 구하는 문제이다.

 

문제를 읽어보면 알겠지만, 서로 연관되어 있는 부분도 많고, 주고 받을 것도 많아 보인다.

 

2. 내가 한 시도

 일단 문제에 얽혀 있는 방향성이 많은 것 같아 Person 이라는 객체를 만들고, 총 5개의 필드(name, report, reported, reportedCount, mailCount)를 만들어 진행했다. 변수명에서 보면 알겠지만 변수가 뜻하는 것은 각각 이름, 내가 신고한사람들, 나를 신고한사람들, 내가 신고당한 횟수, 결과 메일을 받은 횟수이다.

 Person이라는 객체를 만들었으니 그 객체의 상태값에 넣어 줄 데이터만 만들어주면 그만이다. 자세한 것은 아래의 코드를 보면서 이해하자.

 

 1) 일단 객체 검색을 위한 map을 선언한다.

 2) 주어진 데이터를 split해서 신고자와 신고당한사람으로 나누어, 신고자의 report 필드에 당한사람의 이름이 없으면 추가되고, 그렇지 않으면 스킵한다.

 3) 그리고 마찬가지로 신고당한사람도 reported필드에 나를 신고한사람의 이름이 없다면 추가하고, reportedCount도 증가시켜준다.

 4) 모든 데이터가 완성되었다면, k값과 신고당한 횟수를 비교하고, k값보다 많이 신고당한사람은 자기를 신고한사람을 역추적해서 mailCount를 증가시켜준다.

 

3. code

/**
 * 프로그래머스 LV1
 * 신고 결과 받기
 * 접근 방법: Person이라는 객체를 만들고 그 안에 여러가지 정보를 넣어서 해결.
 */
public class Solution {
    public static void main(String[] args) {
        solution(new String[]{"muzi", "frodo", "apeach", "neo"}, // id_list
                new String[]{"muzi frodo", "apeach frodo", "frodo neo", "muzi neo", "apeach muzi"},// 신고자, 신고당한사람
                2);
    }

    public static int[] solution(String[] id_list, String[] report, int k) {
        /*
         * 나중에 리턴할 정답
         */
        int[] answer = new int[id_list.length];

        /*
         * 객체 검색을 위한 map
         */
        Map<String, Person> persons = new HashMap();

        /*
         * 객체를 만들어서 객체검색을 위한 맵에 저장.
         */
        for (int i = 0; i < id_list.length; i++) {
            persons.put(id_list[i], new Person(id_list[i]));
        }

        /*
         *  report 배열을 까서 신고자와 신고당한자(날신고한사람)와 cnt를 객체에 저장하는 로직
         */
        for (int i = 0; i < report.length; i++) {
            String personAndReport = report[i];
            String[] split = personAndReport.split(" ");
            String fromPerson = split[0];
            String toPerson = split[1];
            Person person = persons.get(fromPerson);

            if (!(person.isContainInReport(toPerson))) {
                person.addReport(toPerson); // 신고한사람 리스트에 이름이 없으면 추가
                Person reportedPerson = persons.get(toPerson);
                reportedPerson.addReportedCnt();

                if (!(reportedPerson.isContainInReported(fromPerson))) { //신고 당한사람도 자신을 신고한사람을 배열에 추가
                    reportedPerson.addReported(fromPerson);
                }
            }
        }

        /*
         * 유저객체를 순회하면서 k횟수 보다 같거나 큰 신고횟수를 가지고 있다면 해당 유저를 신고한 유저들의 객체를 찾아 mailCnt ++
         */
        for (String name : persons.keySet()) {
            Person person = persons.get(name);

            if (person.getReportedCnt() >= k) {
                for (int i = 0; i < person.getReportedCnt(); i++) {
                    String reportPersonName = person.getReportedByIndex(i);
                    Person reportPerson = persons.get(reportPersonName);
                    reportPerson.addMailCnt();
                }
            }
        }

        /*
         * 객체를 순회하면서 MailCnt를 정답 배열에 저장.
         */
        for (int i = 0; i < id_list.length; i++) {
            String name = id_list[i];
            Person person = persons.get(name);
            answer[i] = person.getMailCnt();
        }

        return answer;
    }

    static class Person {
        private String name;
        private List<String> report; // 내가 신고한 사람
        private List<String> reported; // 나를 신고한 사람
        private int reportedCnt;
        private int mailCnt;

        public Person(String name) {
            this.name = name;
            this.report = new ArrayList<>();
            this.reported = new ArrayList<>();
            this.reportedCnt = 0;
            this.mailCnt = 0;
        }

        public String getReportByIndex(int index) {
            if (index < 0 || index >= report.size()) {
                throw new IndexOutOfBoundsException();
            }
            return report.get(index);
        }

        public String getReportedByIndex(int index) {
            if (index < 0 || index >= reported.size()) {
                throw new IndexOutOfBoundsException();
            }
            return reported.get(index);
        }

        public void addReport(String name) {
            report.add(name);
        }

        public void addReported(String name) {
            reported.add(name);
        }

        public void addReportedCnt() {
            reportedCnt++;
        }

        public void addMailCnt() {
            mailCnt++;
        }

        public boolean isContainInReport(String name) {
            return report.contains(name);
        }

        public boolean isContainInReported(String name) {
            return reported.contains(name);
        }

        public int getReportedCnt() {
            return reportedCnt;
        }

        public int getMailCnt() {
            return mailCnt;
        }
    }
}

 

4. 깨닫거나 알게된 것.

 이번 문제를 그룹스터디원들과 함께 코드리뷰를 해보았는데, 대부분 중복방지(신고를 여러 번 했을 경우 1번의 횟수로 친다.) 코드를 나처럼 if문으로 해서 조절하지 않고, set을 이용했다. 그래서 앞으로 나도 중복은 1로 쳐주는 것에는 Set이라는 자료구조를 과감히 사용해보자고 다짐했다. (그냥 편한 List로 질러버리는 무지성코딩 지양하자.)

 그래도 요새는 코테 준비하면서 객체만드는 재미에 푹 빠져서 나름 이런 소소한 재미로 근근히 이어나가는 중이다. 앞으로도 객체를 통해서 문제를 해결하는 아이디어가 머릿속에서 펑펑 터졌으면 좋겠다.

 

 

참조

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