코딩테스트

신고 결과 받기, 택배 상자 꺼내기, [PCCP 기출문제] 1번 / 동영상 재생기

Cadi 2025. 2. 21. 17:11

코딩테스트 : 신고 결과 받기 

신입사원 무지는 게시판 불량 이용자를 신고하고 처리 결과를 메일로 발송하는 시스템을 개발하려 합니다. 무지가 개발하려는 시스템은 다음과 같습니다.

각 유저는 한 번에 한 명의 유저를 신고할 수 있습니다.
신고 횟수에 제한은 없습니다. 서로 다른 유저를 계속해서 신고할 수 있습니다.
한 유저를 여러 번 신고할 수도 있지만, 동일한 유저에 대한 신고 횟수는 1회로 처리됩니다.
k번 이상 신고된 유저는 게시판 이용이 정지되며, 해당 유저를 신고한 모든 유저에게 정지 사실을 메일로 발송합니다.
유저가 신고한 모든 내용을 취합하여 마지막에 한꺼번에 게시판 이용 정지를 시키면서 정지 메일을 발송합니다.
다음은 전체 유저 목록이 ["muzi", "frodo", "apeach", "neo"]이고, k = 2(즉, 2번 이상 신고당하면 이용 정지)인 경우의 예시입니다.

유저 ID 유저가 신고한 ID 설명
"muzi" "frodo" "muzi"가 "frodo"를 신고했습니다.
"apeach" "frodo" "apeach"가 "frodo"를 신고했습니다.
"frodo" "neo" "frodo"가 "neo"를 신고했습니다.
"muzi" "neo" "muzi"가 "neo"를 신고했습니다.
"apeach" "muzi" "apeach"가 "muzi"를 신고했습니다.
각 유저별로 신고당한 횟수는 다음과 같습니다.

유저 ID 신고당한 횟수
"muzi" 1
"frodo" 2
"apeach" 0
"neo" 2
위 예시에서는 2번 이상 신고당한 "frodo"와 "neo"의 게시판 이용이 정지됩니다. 이때, 각 유저별로 신고한 아이디와 정지된 아이디를 정리하면 다음과 같습니다.

유저 ID 유저가 신고한 ID 정지된 ID

유저 ID유저가 신고한 ID정지된 ID
"muzi" ["frodo", "neo"] ["frodo", "neo"]
"frodo" ["neo"] ["neo"]
"apeach" ["muzi", "frodo"] ["frodo"]
"neo" 없음 없음


따라서 "muzi"는 처리 결과 메일을 2회, "frodo"와 "apeach"는 각각 처리 결과 메일을 1회 받게 됩니다.

이용자의 ID가 담긴 문자열 배열 id_list, 각 이용자가 신고한 이용자의 ID 정보가 담긴 문자열 배열 report, 정지 기준이 되는 신고 횟수 k가 매개변수로 주어질 때, 각 유저별로 처리 결과 메일을 받은 횟수를 배열에 담아 return 하도록 solution 함수를 완성해주세요.

using System;
using System.Collections.Generic;
using System.Linq;
public class Solution {
    public int[] solution(string[] id_list, string[] report, int k)
    {
        int[] answer = new int[id_list.Length];
        
        //신고 당한 사람 기준으로 .. . . . . . . . . . 
        // 자신을 신고한 사람의 리스트를 갖고 있어야 함. 
        
        //혹은 신고한 사람이 자신이 신고한 사람 리스트를 쭈욱 순회하면서
        // k 이상인 사람들의 수를 셈
        Dictionary<string,int> reportTimes = new Dictionary<string,int>();
        Dictionary<string, int> id = new Dictionary<string, int>();

        for (int i = 0; i < id_list.Length; i++)
        {
            reportTimes.Add(id_list[i],0);
            id.Add(id_list[i],i);
        }
      
        report = report.Distinct().ToArray();

        for (int i = 0; i < report.Length; i++)
        {
            string[] temp = report[i].Split(' ');
            string reported = temp[1];
            
            reportTimes[reported]++;
        }
        
        for (int i = 0; i < report.Length; i++)
        {
            string[] temp = report[i].Split(' ');
            string reporting = temp[0];
            string reported = temp[1];

            if (reportTimes[reported] >= k) answer[id[reporting]]++;
        }
        return answer;
    }
}

 

위에 적어둔 두 가지 방법 중 어느 것이 더 편할지, 어떤 것이 용량을 더 적게, 시간은 더 빠르게 할 수 있을지 

계속 고민하다가 시간만 가길래 일단 풀었다. 

 

두 번째 방법으로 해보고 싶었으나, 결국 리폿당한 사람이 리폿한 사람의 리스트를 갖고 있다가 메세지를 보내야 하기 때문에 첫 번째 방법과 크게 다르지 않을 것 같아 구현이 쉬워보이는 방향으로 나갔다. 

 

Dictionary를 두 개는 쓰고 싶지 않았으나 다른 방법이 생각나지 않아 이렇게 풀었다. 

다른 분들의 풀이를좀 잘 봐야겠다. 

 

 

다른 사람의 흥미로운 풀이

 

 

무려.... 린큐로 하신 분이 계신다. 봐도 다시 하라하면 못할듯 하다. 

 

참고할만한 풀이로는 Array.Indexof()를 쓰신 분이 계셨다. 

사실 IndexOf라는 함수가 뭔지 몰라서 못쓴 부분도 있긴 하다. 

다만, 생각해야 할 점은 IndexOf라는 함수도 결국 순환하면서 찾는 것이기에 배열의 크기가 커진다면 적합하지 않을 수도 있다.

 

코딩테스트 : 택배 상자 꺼내기

1 ~ n의 번호가 있는 택배 상자가 창고에 있습니다. 당신은 택배 상자들을 다음과 같이 정리했습니다.

왼쪽에서 오른쪽으로 가면서 1번 상자부터 번호 순서대로 택배 상자를 한 개씩 놓습니다. 가로로 택배 상자를 w개 놓았다면 이번에는 오른쪽에서 왼쪽으로 가면서 그 위층에 택배 상자를 한 개씩 놓습니다. 그 층에 상자를 w개 놓아 가장 왼쪽으로 돌아왔다면 또다시 왼쪽에서 오른쪽으로 가면서 그 위층에 상자를 놓습니다. 이러한 방식으로 n개의 택배 상자를 모두 놓을 때까지 한 층에 w개씩 상자를 쌓습니다.

 

 

위 그림은 w = 6일 때 택배 상자 22개를 쌓은 예시입니다.
다음 날 손님은 자신의 택배를 찾으러 창고에 왔습니다. 당신은 손님이 자신의 택배 상자 번호를 말하면 해당 택배 상자를 꺼내줍니다. 택배 상자 A를 꺼내려면 먼저 A 위에 있는 다른 모든 상자를 꺼내야 A를 꺼낼 수 있습니다. 예를 들어, 위 그림에서 8번 상자를 꺼내려면 먼저 20번, 17번 상자를 꺼내야 합니다.

당신은 꺼내려는 상자 번호가 주어졌을 때, 꺼내려는 상자를 포함해 총 몇 개의 택배 상자를 꺼내야 하는지 알고 싶습니다.

창고에 있는 택배 상자의 개수를 나타내는 정수 n, 가로로 놓는 상자의 개수를 나타내는 정수 w와 꺼내려는 택배 상자의 번호를 나타내는 정수 num이 매개변수로 주어집니다. 이때, 꺼내야 하는 상자의 총개수를 return 하도록 solution 함수를 완성해 주세요.

using System;

public class Solution {
    public int solution(int n, int w, int num) 
    {
        int answer = 0;
        
        bool right = true;
        
        
        int temp = num;
        
        while(temp <= n)
        {
            if ((temp / w) % 2 == 0) right = true;
            else right = false;
            if(right)
            {
                int rightEnd = temp % w == 0 ? temp : w * ((temp/w)+1);
                temp += (rightEnd-temp) * 2 + 1;
            }
            else{
                int leftEnd = temp % w == 0 ? temp :  w * ((temp/w)+1);
                temp +=(leftEnd-temp) * 2 + 1;
            }
            answer++;
        }
    
        
        
        return answer;
    }
}

다른 사람의 흥미로운 풀이

 

나름 이쁘게 잘 푼 것 같다. 

 

코딩테스트 : [PCCP 기출문제] 1번 / 동영상 재생기

당신은 동영상 재생기를 만들고 있습니다. 당신의 동영상 재생기는 10초 전으로 이동, 10초 후로 이동, 오프닝 건너뛰기 3가지 기능을 지원합니다. 각 기능이 수행하는 작업은 다음과 같습니다.

10초 전으로 이동: 사용자가 "prev" 명령을 입력할 경우 동영상의 재생 위치를 현재 위치에서 10초 전으로 이동합니다. 현재 위치가 10초 미만인 경우 영상의 처음 위치로 이동합니다. 영상의 처음 위치는 0분 0초입니다.
10초 후로 이동: 사용자가 "next" 명령을 입력할 경우 동영상의 재생 위치를 현재 위치에서 10초 후로 이동합니다. 동영상의 남은 시간이 10초 미만일 경우 영상의 마지막 위치로 이동합니다. 영상의 마지막 위치는 동영상의 길이와 같습니다.
오프닝 건너뛰기: 현재 재생 위치가 오프닝 구간(op_start ≤ 현재 재생 위치 ≤ op_end)인 경우 자동으로 오프닝이 끝나는 위치로 이동합니다.
동영상의 길이를 나타내는 문자열 video_len, 기능이 수행되기 직전의 재생위치를 나타내는 문자열 pos, 오프닝 시작 시각을 나타내는 문자열 op_start, 오프닝이 끝나는 시각을 나타내는 문자열 op_end, 사용자의 입력을 나타내는 1차원 문자열 배열 commands가 매개변수로 주어집니다. 이때 사용자의 입력이 모두 끝난 후 동영상의 위치를 "mm:ss" 형식으로 return 하도록 solution 함수를 완성해 주세요.

using System;

public class Solution {
    public string solution(string video_len, string pos, string op_start, string op_end, string[] commands)
    {


        int temp = int.Parse(pos.Replace(":", ""));
        int openstart = int.Parse(op_start.Replace(":", ""));
        int openend = int.Parse(op_end.Replace(":", ""));
        int videolen = int.Parse(video_len.Replace(":", ""));
        
        for (int i = 0; i < commands.Length; i++)
        {
            if (temp >= openstart && temp <= openend) temp = openend;

            if (commands[i] == "prev")
            {
                if (temp % 100 < 10) temp -= 50;
                else temp -= 10;
                if (temp < 0) temp = 0;
            }
            else if (commands[i] == "next")
            {
                temp += 10;
                if (temp % 100 >= 60) temp += 40;
                if (temp > videolen) temp = videolen;
            }
            if (temp >= openstart && temp <= openend) temp = openend;

        }

        string time = (temp / 100).ToString();
        string minute = (temp % 100).ToString();
        time = time.Length > 1 ? time : "0" + time;
        minute = minute.Length > 1 ? minute : "0" + minute;
        return time + ":" + minute;
    }
}

 

어제 유연근무제에서 풀었던 방식을 응용했다.

문제가 좀 불친절한 것 같아서 15~20분 걸린 것 같다. (사실 내가 예제 3을 제대로 안읽어서 순서를 잘못했다)

 

다른 사람의 흥미로운 풀이

 

모두 초로 변환해서 푸신 분이 계시다. 좋은 것 같다. 

만일 다른 많은 조건들이 추가된다면 예외처리를 하나의 함수로 묶어서도 풀 수 있을듯 하다. 

 

 


프로그래머스 레벨 1(C# 기준) 71문제를 거의 다 풀어간다. 약 2주정도 걸렸는데 흠... 2단계를 풀어야 할 지

백준을 다시 가서 공부를 좀 하다가 넘어올지 고민중이다.