코딩테스트

성격 유형 검사하기, 바탕화면 정리, 개인정보 수집 유효기간

Cadi 2025. 2. 19. 23:29

코딩테스트 : 성격 유형 검사하기

문제 설명
나만의 카카오 성격 유형 검사지를 만들려고 합니다.
성격 유형 검사는 다음과 같은 4개 지표로 성격 유형을 구분합니다. 성격은 각 지표에서 두 유형 중 하나로 결정됩니다.

지표 번호 성격 유형
1번 지표 라이언형(R), 튜브형(T)
2번 지표 콘형(C), 프로도형(F)
3번 지표 제이지형(J), 무지형(M)
4번 지표 어피치형(A), 네오형(N)
4개의 지표가 있으므로 성격 유형은 총 16(=2 x 2 x 2 x 2)가지가 나올 수 있습니다. 예를 들어, "RFMN"이나 "TCMA"와 같은 성격 유형이 있습니다.

검사지에는 총 n개의 질문이 있고, 각 질문에는 아래와 같은 7개의 선택지가 있습니다.

매우 비동의
비동의
약간 비동의
모르겠음
약간 동의
동의
매우 동의
각 질문은 1가지 지표로 성격 유형 점수를 판단합니다.

예를 들어, 어떤 한 질문에서 4번 지표로 아래 표처럼 점수를 매길 수 있습니다.

선택지 성격 유형 점수
매우 비동의 네오형 3점
비동의 네오형 2점
약간 비동의 네오형 1점
모르겠음 어떤 성격 유형도 점수를 얻지 않습니다
약간 동의 어피치형 1점
동의 어피치형 2점
매우 동의 어피치형 3점
이때 검사자가 질문에서 약간 동의 선택지를 선택할 경우 어피치형(A) 성격 유형 1점을 받게 됩니다. 만약 검사자가 매우 비동의 선택지를 선택할 경우 네오형(N) 성격 유형 3점을 받게 됩니다.

위 예시처럼 네오형이 비동의, 어피치형이 동의인 경우만 주어지지 않고, 질문에 따라 네오형이 동의, 어피치형이 비동의인 경우도 주어질 수 있습니다.
하지만 각 선택지는 고정적인 크기의 점수를 가지고 있습니다.

매우 동의나 매우 비동의 선택지를 선택하면 3점을 얻습니다.
동의나 비동의 선택지를 선택하면 2점을 얻습니다.
약간 동의나 약간 비동의 선택지를 선택하면 1점을 얻습니다.
모르겠음 선택지를 선택하면 점수를 얻지 않습니다.
검사 결과는 모든 질문의 성격 유형 점수를 더하여 각 지표에서 더 높은 점수를 받은 성격 유형이 검사자의 성격 유형이라고 판단합니다. 단, 하나의 지표에서 각 성격 유형 점수가 같으면, 두 성격 유형 중 사전 순으로 빠른 성격 유형을 검사자의 성격 유형이라고 판단합니다.

질문마다 판단하는 지표를 담은 1차원 문자열 배열 survey와 검사자가 각 질문마다 선택한 선택지를 담은 1차원 정수 배열 choices가 매개변수로 주어집니다. 이때, 검사자의 성격 유형 검사 결과를 지표 번호 순서대로 return 하도록 solution 함수를 완성해주세요.

using System;
using System.Collections.Generic;
using System.Linq;
public class Solution
{
    string[] type = { "R", "T", "C", "F", "J", "M", "A", "N" };

    public string solution(string[] survey, int[] choices)
    {
        string answer = "";
       
        Dictionary<string, int> dic = new Dictionary<string, int>();

        foreach (string c in type)
        {
            dic.Add(c, 0);
        }

        for (int i = 0; i < choices.Length; i++)
        {
           string[] temp = survey[i].ToCharArray().Select(x => x.ToString()).ToArray();
           
           string first = temp[0];
           string second = temp[1];

           if (choices[i] < 4)
           {
               if (choices[i] == 1) dic[first] += 3;
               else if (choices[i] == 2) dic[first] += 2;
               else if (choices[i] == 3) dic[first] += 1;
           }
           else if (choices[i] > 4)
           { 
               dic[second] += choices[i]-4;
           }
           
        }
        
       answer += dic["R"] >= dic["T"] ? "R" : "T";
       answer += dic["C"] >= dic["F"] ? "C" : "F";
       answer += dic["J"] >= dic["M"] ? "J" : "M";
       answer += dic["A"] >= dic["N"] ? "A" : "N";
        
        
        return answer;
    }


    
}

다른 사람의 흥미로운 풀이

 

이건... 잘썼다기 보다는 다른 분이 338줄짜리 코드가 있어서 오랜만에 빵 터졌다. 

결국 이런걸 공부하는 과정인가보다. 단순하게도 처리할 수 있지만 조금 더 효율적으로 하기 위한 방법을 고안하는 ! 

 

 

 

 

코딩테스트 : 바탕화면 정리

문제 설명

코딩테스트를 준비하는 머쓱이는 프로그래머스에서 문제를 풀고 나중에 다시 코드를 보면서 공부하려고 작성한 코드를 컴퓨터 바탕화면에 아무 위치에나 저장해 둡니다. 저장한 코드가 많아지면서 머쓱이는 본인의 컴퓨터 바탕화면이 너무 지저분하다고 생각했습니다. 프로그래머스에서 작성했던 코드는 그 문제에 가서 다시 볼 수 있기 때문에 저장해 둔 파일들을 전부 삭제하기로 했습니다.

컴퓨터 바탕화면은 각 칸이 정사각형인 격자판입니다. 이때 컴퓨터 바탕화면의 상태를 나타낸 문자열 배열 wallpaper가 주어집니다. 파일들은 바탕화면의 격자칸에 위치하고 바탕화면의 격자점들은 바탕화면의 가장 왼쪽 위를 (0, 0)으로 시작해 (세로 좌표, 가로 좌표)로 표현합니다. 빈칸은 ".", 파일이 있는 칸은 "#"의 값을 가집니다. 드래그를 하면 파일들을 선택할 수 있고, 선택된 파일들을 삭제할 수 있습니다. 머쓱이는 최소한의 이동거리를 갖는 한 번의 드래그로 모든 파일을 선택해서 한 번에 지우려고 하며 드래그로 파일들을 선택하는 방법은 다음과 같습니다.

  • 드래그는 바탕화면의 격자점 S(lux, luy)를 마우스 왼쪽 버튼으로 클릭한 상태로 격자점 E(rdx, rdy)로 이동한 뒤 마우스 왼쪽 버튼을 떼는 행동입니다. 이때, "점 S에서 점 E로 드래그한다"고 표현하고 점 S와 점 E를 각각 드래그의 시작점, 끝점이라고 표현합니다.
  • 점 S(lux, luy)에서 점 E(rdx, rdy)로 드래그를 할 때, "드래그 한 거리"는 |rdx - lux| + |rdy - luy|로 정의합니다.
  • 점 S에서 점 E로 드래그를 하면 바탕화면에서 두 격자점을 각각 왼쪽 위, 오른쪽 아래로 하는 직사각형 내부에 있는 모든 파일이 선택됩니다.

예를 들어 wallpaper = [".#...", "..#..", "...#."]인 바탕화면을 그림으로 나타내면 다음과 같습니다.


이러한 바탕화면에서 다음 그림과 같이 S(0, 1)에서 E(3, 4)로 드래그하면 세 개의 파일이 모두 선택되므로 드래그 한 거리 (3 - 0) + (4 - 1) = 6을 최솟값으로 모든 파일을 선택 가능합니다.


(0, 0)에서 (3, 5)로 드래그해도 모든 파일을 선택할 수 있지만 이때 드래그 한 거리는 (3 - 0) + (5 - 0) = 8이고 이전의 방법보다 거리가 늘어납니다.

머쓱이의 컴퓨터 바탕화면의 상태를 나타내는 문자열 배열 wallpaper가 매개변수로 주어질 때 바탕화면의 파일들을 한 번에 삭제하기 위해 최소한의 이동거리를 갖는 드래그의 시작점과 끝점을 담은 정수 배열을 return하는 solution 함수를 작성해 주세요. 드래그의 시작점이 (lux, luy), 끝점이 (rdx, rdy)라면 정수 배열 [lux, luy, rdx, rdy]를 return하면 됩니다.

 

using System;

public class Solution {
    public int[] solution(string[] wallpaper) 
    {
        int[] answer = new int[] {};
        
        int maxRow = int.MinValue, maxCol = int.MinValue;
        int minRow = int.MaxValue, minCol = int.MaxValue;

        for (int row = 0; row < wallpaper.Length; row++)
        {
            for (int col = 0; col < wallpaper[row].Length; col++)
            {
                if (wallpaper[row][col] == '#')
                {
                    if (row < minRow) minRow = row;
                    if (row > maxRow) maxRow = row;
                    if (col < minCol) minCol = col;
                    if (col > maxCol) maxCol = col;
                }
            }
        }
        
        
        
        return new int[ ]{minRow, minCol, maxRow+1, maxCol+1};
        

        return answer;
    }
}

다른 사람의 흥미로운 풀이

answer 자체에 처음부터 maxValue, maxValue, 0 , 0 을 선언해두고

순회하면서 계속 비교 한 후 출력하면 되는 문제였다. 조금 더 깔끔할 수 있었다.

 

 

 

코딩테스트 :  개인정보 수집 유효기간 

문제 설명
고객의 약관 동의를 얻어서 수집된 1~n번으로 분류되는 개인정보 n개가 있습니다. 약관 종류는 여러 가지 있으며 각 약관마다 개인정보 보관 유효기간이 정해져 있습니다. 당신은 각 개인정보가 어떤 약관으로 수집됐는지 알고 있습니다. 수집된 개인정보는 유효기간 전까지만 보관 가능하며, 유효기간이 지났다면 반드시 파기해야 합니다.

예를 들어, A라는 약관의 유효기간이 12 달이고, 2021년 1월 5일에 수집된 개인정보가 A약관으로 수집되었다면 해당 개인정보는 2022년 1월 4일까지 보관 가능하며 2022년 1월 5일부터 파기해야 할 개인정보입니다.
당신은 오늘 날짜로 파기해야 할 개인정보 번호들을 구하려 합니다.

모든 달은 28일까지 있다고 가정합니다.

다음은 오늘 날짜가 2022.05.19일 때의 예시입니다.

약관 종류 유효기간
A 6 달
B 12 달
C 3 달
번호 개인정보 수집 일자 약관 종류
1 2021.05.02 A
2 2021.07.01 B
3 2022.02.19 C
4 2022.02.20 C
첫 번째 개인정보는 A약관에 의해 2021년 11월 1일까지 보관 가능하며, 유효기간이 지났으므로 파기해야 할 개인정보입니다.
두 번째 개인정보는 B약관에 의해 2022년 6월 28일까지 보관 가능하며, 유효기간이 지나지 않았으므로 아직 보관 가능합니다.
세 번째 개인정보는 C약관에 의해 2022년 5월 18일까지 보관 가능하며, 유효기간이 지났으므로 파기해야 할 개인정보입니다.
네 번째 개인정보는 C약관에 의해 2022년 5월 19일까지 보관 가능하며, 유효기간이 지나지 않았으므로 아직 보관 가능합니다.
따라서 파기해야 할 개인정보 번호는 [1, 3]입니다.

오늘 날짜를 의미하는 문자열 today, 약관의 유효기간을 담은 1차원 문자열 배열 terms와 수집된 개인정보의 정보를 담은 1차원 문자열 배열 privacies가 매개변수로 주어집니다. 이때 파기해야 할 개인정보의 번호를 오름차순으로 1차원 정수 배열에 담아 return 하도록 solution 함수를 완성해 주세요.

using System;
using System.Collections.Generic;
using System.Linq;

public class Solution
{
    public int[] solution(string today, string[] terms, string[] privacies)
    {
        List<int> list = new List<int>();
        //유형과 유효기간(달) 들어감
        Dictionary<string, int> dict = new Dictionary<string, int>();
        
        int[] today2 = today.Split('.').Select(int.Parse).ToArray();
        int todaydate = today2[0] * 336 + today2[1] * 28 +
                        today2[2];
        for (int i = 0; i < terms.Length; i++)
        {
            string[] temp = terms[i].Split(' ');
            dict.Add(temp[0], int.Parse(temp[1]));
        }

        for (int i = 0; i < privacies.Length; i++)
        {
            string[] temp = privacies[i].Split(' ');
            string[] date = temp[0].Split('.');

            int tempdate = int.Parse(date[0]) * 336 + int.Parse(date[1]) * 28 + int.Parse(date[2]) - 1;
            tempdate += dict[temp[1]] * 28;

            if (tempdate < todaydate)
            {
                list.Add(i+1);
            }
        }

        return list.ToArray();
    }
}

 

하나씩 올리는거 귀찮아서 그냥 다 곱해서 큰 숫자로 풀었다. 

생각해보니 뒤에 두 자리 (제한사항에서 2000~ 2022였으므로)로 풀어도 되었을 것 같다. 

 

다른 사람의 흥미로운 풀이

 

오... 이런 방식으로 할 거면, 굳이 번거롭게 두 번 계산하지 말고, 한 번에 계산해도 된다. 

예를 들어서, tempdate += dict[temp[1]] * 28을 더해주지 말고 그냥 위에다 더해버려도 된다.

왜냐하면 실제로 15월은 없지만 곱해서 계산하면 같은 값이 나오기 때문이다. 

 

 


오늘은 그리 어렵지 않은 세 문제를 풀었다. 앞으로도 이런 식으로 실력이 늘면서 점점 풀었으면 좋겠다.