Coding Test/Programmers

[Lv.1] 성격 유형 검사하기 [프로그래머스_코딩테스트] [2022 KAKAO TECH INTERNSHIP]

whawoo 2025. 5. 11. 04:49
반응형

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

 

프로그래머스

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

programmers.co.kr

using System;

public class Solution
{
    /// <summary>
    /// 성격 유형 검사하기
    /// https://school.programmers.co.kr/learn/courses/30/lessons/118666
    /// </summary>
    public string solution(string[] survey, int[] choices)
    {
        // choice가 양의 정수로만 되어 있는데 합산하기 편하기 위해서 모르겠음을 0을 기준으로 두고 계산
        const int BalanceNumber = 4;
        // answer를 내기 위한 choice 합산 (한 번도 안 들어 온 경우 null);
        int?[] choiceArr = { null, null, null, null };
        var keywords = new []{ "RT", "CF", "JM", "AN" };
        var rKeywords = new []{ "TR", "FC", "MJ", "NA" };
        
        string answer = "";

        for (int i = 0; i < survey.Length; i++)
        {
            int surveyIndex = 0;
            int choiceVal = choices[i];
            // 모르겠음을 0으로 만들기 위함
            choiceVal -= BalanceNumber;

            string cSurvey = survey[i];
            
            // 역방향인 경우
            if (Array.FindIndex(rKeywords, (x) => x == cSurvey) >= 0)
            {
                surveyIndex = Array.FindIndex(rKeywords, (x) => x == cSurvey);
            }
            else
            {
                choiceVal *= -1;
                
                surveyIndex = Array.FindIndex(keywords, (x) => x == cSurvey);
            }

            if (choiceArr[surveyIndex] == null)
            {
                choiceArr[surveyIndex] = 0;
            }
            
            choiceArr[surveyIndex] += choiceVal;
        }

        // 순서대로 합계 점수
        for (int cIndex = 0; cIndex < choiceArr.Length; cIndex++)
        {
            // 한번도 점수가 계산 안된 경우거나 합계가 0인 경우 사전 순으로 빠른 성격 유형 (keywords)
            if (choiceArr[cIndex] == null || choiceArr[cIndex] == 0)
            {
                // 순서는 같고. 첫번째 유형을 골라냄
                answer += keywords[cIndex][0];
            }
            else
            {
                answer += (choiceArr[cIndex] > 0 ? keywords[cIndex][0] : keywords[cIndex][1]);
            }
        }
        
        
        return answer;
    }
}

/// <summary>
/// C# 7.3
/// </summary>
internal class Program
{
    public static void Main(string[] args)
    {
        var sl = new Solution();
        string[] survey = { "TR", "RT", "TR" };
        int[] choices = { 7, 1, 3};
        Console.WriteLine(sl.solution(survey, choices));
    }
}

 

문제의 길이가 기존 연습문제들에 비해서 꽤나 길어져서 나와서 생각보다 코드가 지저분하고 복잡해진 결과물.. 일단 MBTI의 카카오 버젼 같은 느낌으로 보이는데 선택지에 따른 성격 유형 점수를 계산할 때 비동의는 음수, 동의는 양수로 해서 합산을 하는 형태로 하는 것에 포커스를 맞추었다. 다만 여기서 Survey라는 것이 주어지는데 비동의와 동의가 문제에 따라 뒤집힐 수 있다는 거에서 혼동을 일으킨 부분. 알고리즘 문제를 꼬아서 내기 위해서 한 것이라 생각되긴 하는데 (실제 MBTI에서도 비슷하게 뒤집혀 있는 것은 본 듯 하다) 그 때 쉽게 생각을 했어야 하는 것을 괜히 keywords를 뒤집은 거와 아닌 것을 나눠서 코드만 복잡하게 만들었다.

 

그렇게 해서 나온 결과물은 위와 같은 형태인데.. 내가 봐도 코드가 복잡하긴 하다. 그래서 역시 이 부분도 피드백은 chatgpt에게 물어보고 방향을 바꿔보았다. 일단 결과물 먼저 보기로 한다.

public string solution(string[] survey, int[] choices)
{
    var scores = new Dictionary<char, int>
    {
        { 'R', 0 }, { 'T', 0 },
        { 'C', 0 }, { 'F', 0 },
        { 'J', 0 }, { 'M', 0 },
        { 'A', 0 }, { 'N', 0 }
    };

    for (int i = 0; i < survey.Length; i++)
    {
        char disagree = survey[i][0];
        char agree = survey[i][1];
        int choice = choices[i];

        if (choice < 4)
            scores[disagree] += 4 - choice;
        else if (choice > 4)
            scores[agree] += choice - 4;
    }

    var result = new StringBuilder();
    result.Append(scores['R'] >= scores['T'] ? 'R' : 'T');
    result.Append(scores['C'] >= scores['F'] ? 'C' : 'F');
    result.Append(scores['J'] >= scores['M'] ? 'J' : 'M');
    result.Append(scores['A'] >= scores['N'] ? 'A' : 'N');

    return result.ToString();
}

 

정말 깔끔하게 나온 결과물..

 

일단 내가 포커스로 두었던 선택지를 합산하는거는 동일하게 4를 0으로 두고 비동의를 음수, 동의를 양수로 두고 합산 시키는 건 같다. 다만 여기서 핵심으로 볼 부분으로 여겨지는 건 Dictionary로 매핑을 해서 각 유형별로 점수를 기록해두는 것이고 그 값을 토대로 마지막에 성격유형을 출력만 해주면 된다.

 

그리고 두번째로 포커스로 잡을 것은 survey로 입력받은 유형의 첫번째가 disagree, 두번째가 agree를 가리키는 것으로 문자의 위치에 따라서 역할을 부여하는 것이었다.

 

그렇게 해서 하게 되면 굳이 필자가 처음에 짠 코드처럼 keywors, rKeywords와 같은 지저분한 코드를 짤 필요가 없다.. 그리고 그렇게 하다 보니 나온 FindIndex 역시 마찬가지로 효율도 안좋다.. (프로그래머스에서 통과는 되긴 하던..)

 

3번째 포커스로 잡는다고 하면 string에 appen시 StringBuilder를 사용해서 높인다는 것도 기억해두면 좋을 듯 하다. string은 쉽게 사용하려면 그냥 += 와 같이 더해버리는 형태로 쓰기도 하나 이건 몇번 하지 않는 지금과 같은 문제인 경우에만 하는 것이 낫다. string += 를 반복적으로 많이 사용하게 되면 heap 할당이 새로 계속 일어나서 메모리 재할당과 GC문제가 생기게 된다. 그러나 append를 하는 형태로 사용하게 되면 내부적으로 가변 버퍼를 사용하고 있어서 메모리 확장을 필요한 순간만 하여 복사에 드는 비용이 줄어든 다고 한다. 실제로 1~10000까지 스트링을 appen하는 것으로 비교하면 시간 차이가 5~20배는 난다고 한다.

반응형