Algorithm/Programmers

[프로그래머스] 코딩테스트 연습 - 성격 유형 검사하기(Java, C)

코끼리 개발자 2022. 12. 7. 23:34
728x90
SMALL

-링크

https://school.programmers.co.kr/learn/courses/30/lessons/118666?language=c 

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

-문제 설명

나만의 카카오 성격 유형 검사지를 만들려고 합니다.
성격 유형 검사는 다음과 같은 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 함수를 완성해주세요.

 

 

-제한사항 

  • 1 ≤ survey의 길이 ( = n) ≤ 1,000
    • survey의 원소는 "RT", "TR", "FC", "CF", "MJ", "JM", "AN", "NA" 중 하나입니다.
    • survey[i]의 첫 번째 캐릭터는 i+1번 질문의 비동의 관련 선택지를 선택하면 받는 성격 유형을 의미합니다.
    • survey[i]의 두 번째 캐릭터는 i+1번 질문의 동의 관련 선택지를 선택하면 받는 성격 유형을 의미합니다.
  • choices의 길이 = survey의 길이
    • choices[i]는 검사자가 선택한 i+1번째 질문의 선택지를 의미합니다.
    • 1 ≤ choices의 원소 ≤ 7
    choices                                     뜻
    1 매우 비동의
    2 비동의
    3 약간 비동의
    4 모르겠음
    5 약간 동의
    6 동의
    7 매우 동의

 

 

-입출력 예

["AN", "CF", "MJ", "RT", "NA"] [5, 3, 2, 7, 5] "TCMA"
["TR", "RT", "TR"] [7, 1, 3] "RCJA"

 

입출력 예 #2(예외 사항을 설명한 것 같아서 #2번 만 갖고왔습니다.)

1번부터 3번까지 질문의 성격 유형 점수를 합치면 아래 표와 같습니다.

지표 번호성격 유형점수성격 유형점수

1번 지표 라이언형(R) 6 튜브형(T) 1
2번 지표 콘형(C) 0 프로도형(F) 0
3번 지표 제이지형(J) 0 무지형(M) 0
4번 지표 어피치형(A) 0 네오형(N) 0

1번 지표는 튜브형(T)보다 라이언형(R)의 점수가 더 높습니다. 따라서 첫 번째 지표의 성격 유형은 R입니다.
하지만, 2, 3, 4번 지표는 모두 0점으로 동일한 점수입니다. 따라서 2, 3, 4번 지표의 성격 유형은 사전순으로 빠른 C, J, A입니다.

따라서 "RCJA"를 return 해야 합니다.

 

 

 

-해설

문제가 일단 너무너무 길고 상세히 설명 되어있어서 덜컥 겁부터 나겠지만 차근차근 읽어보면 굉장히 간단한 쉬운 문제이다.

문제설명에서 보여준 "지표 번호성격 유형" 을 보면 4가지 유형 만 존재한다. 이 부분이 굉장히 쉽게 접근할 수 있는 시그널이다.

그냥 하드코딩으로 선언만 해도 풀리는 문제이기 때문이다. 

나 같은 경우에는, CASE문과 For문을 사용하여 풀어보았는데 For문이 더 빠르게 작동해서 For문으로 제출했다.

우선 주어진 파라미터 중 survey배열의 길이와 choice 배열의 길이가 같기 때문에 survey의 첫 번째 배열의 응답 점수가 choice첫 번째 배열과 같다는 것을 알 수 있다. 

 

survey배열은 문자열 일차원배열이라고 설명되어있지만 사실 이중배열이다. 근데 주어진 survey의 문자열은 항상 2자리인 것을 제약사항을 통해 알 수 있다.

첫 번째 배열을 예로 들면 배열의 첫 번째 문자는 ex)survey[i][0] 부정적인 응답에 점수를 부여 할 지표이고(매우비동의, 비동의, 약간비동의) 배열의 두 번째 문자는 긍정적인 응답에 점수를 부여 할 지표이다(매우동의, 동의, 약간동의). 

이 응답의 기준은 가운데 값인 4를 기준으로 나뉘면서, 값이 4일 경우 어느 쪽에도 점수를 부여하지 않으므로 계산 할 필요가 없다는 것을 알 수 있다.

 

그래서 choices배열의 값이 4인 경우 그냥 continue를 통해 넘겨버리면 된다.

choices배열의 값은 점수의 지표로 사용할 수 있는데 각 응답에 따른 점수가 항상 고정적이기 때문에 score배열을 { 3 , 2, 1, 0, 1, 2, 3}으로 하드코딩하여 사용하면 된다.

여기서 주의 할 점은 choice의 응답이 곧 점수인데, choices는 1~7까지의 값이고 그 값에 따른 점수 값을 score배열에 저장 해 놓았기 때문에 choice값을 통해 바로 점수로 변환하려면 배열은 0번부터 시작이므로 choices의 값 -1 을 한 위치에 접근하여 점수를 도출 해 내면 된다.

 

그럼 여기서 어느 지표에 점수를 줘야 하는지만 남았는데, 지표값은 위에서 설명한 것과 같이 항상 2자리이며 배열의 첫 번째 값은 부정적인 응답에 점수를 부여 할 지표이고 배열의 두 번째 문자는 긍정적인 응답에 점수를 부여 할 지표이기 때문에,

이 말의 의미는 choices의 값이 4보다 크면 긍정적인 응답이므로 배열의 두번째 문자를 참조하여 지표 값에 score배열의  choice[i]-1번째 점수를 주면 되고, 4보다 작은 경우 배열의 첫 번째 지표값에  score배열의  choice[i]-1번째 점수를 주면 된다.

 

이제 점수를 다 환산 했으니 성격 유형을 도출하면 되는데, "지표 번호성격 유형"은 1~4번 지표로 나올 수 있는 값이 항상 동일하다.

때문에 "지표 번호성격 유형"을 1차원 배열에 선언하고, 어떤 지표값의 점수가 더 큰지는 for문을 돌려 지표 번호 성격 유형에 차례로 접근하되, for문의 증가식은 2씩 증가하게 하여 2개씩 차례로 비교하면 된다.

1차원 배열을 2차원 배열처럼 사용하면 더 쉽게 접근할 수 있다.

아래 C 풀이에서는 구조체와 enum을 사용한 방식과 case문을 사용한 방식 두 방법으로 풀어보았으니 참고하여 더 이해가 잘 가는 쪽으로 이해하면 도움이 될 것이다.(사실 구조체도 case문도 안쓰고 Java 풀이처럼 인덱스 참조해서 풀어도 됨 완성까지는 그게 훨씬 더 빠름;;ㅎ)

개인적으로 나는 구조체와 enum을 사용하는 방식이 가독성이 더 좋아서 현업에서 즐겨 사용하는 편이다.

 

 

-풀이(Java)

class Solution {
    int[] indicatorsScore = {3, 2, 1, 0, 1, 2, 3};
    char[] indicators = {'R','T','C','F','J','M','A','N'};
    
    public String solution(String[] survey, int[] choices) {
        String answer = "";
        int[] myScore = new int[8];
        char target;
        
        for(int i = 0; i < survey.length; i++){
            if(choices[i] == 4) continue;
            target = choices[i] < 4 ? survey[i].charAt(0) : survey[i].charAt(1);
            for(int j = 0; j < 8; j++){
                if(target == indicators[j]){
                    myScore[j] += indicatorsScore[choices[i] -1];
                    break;
                }  
            }
        }
        
        for(int i = 0; i < 8; i+=2){
            answer += myScore[i] < myScore[i+1] ? indicators[i+1] : indicators[i];  
        }
        return answer;
    }
}

 

-풀이(C 구조체와 Enum사용)

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

enum
{
    R = 0, T, C, F, J, M, A, N, MAX_INDICATORS_INDEX,
};

typedef struct INDICATORS_CODE_
{
    int  index;
    char code;
} INDICATORS_CODE;

INDICATORS_CODE INDICATORS_CODE_LIST[MAX_INDICATORS_INDEX] =
{
    R,            'R', 
    T,            'T', 
    C,            'C', 
    F,            'F', 
    J,            'J', 
    M,            'M', 
    A,            'A', 
    N,            'N', 
};

int indicators_score[7] = {3, 2, 1, 0, 1, 2, 3} ;

char* solution(const char* survey[], size_t survey_len, int choices[], size_t choices_len) {
    char* answer = (char*)malloc(4+1);
    int my_score[MAX_INDICATORS_INDEX] = {0,};
    int choice = 0;
    char category = '\0';
    int pos = 0;
    
    memset(answer, 0x00, 4+1);
    
    for(int i = 0; i < choices_len; i++)
    {
        if((choice = choices[i]) == 4) continue;
        
        category = choice < 4 ? survey[i][0] : survey[i][1];
        
        for(int j = 0; j < MAX_INDICATORS_INDEX; j++){
            if(INDICATORS_CODE_LIST[j].code == category){
                my_score[INDICATORS_CODE_LIST[j].index]+=indicators_score[choice-1];
                break;
            }
        }
    }
    
    for(int i = 0; i < 8; i+=2){
        answer[pos++] = my_score[i] < my_score[i+1]? 
                        INDICATORS_CODE_LIST[i+1].code : INDICATORS_CODE_LIST[i].code;
    }
    
    
    return answer;
}

 

-풀이(C Case문 사용)

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int indicators_score[7] = {3, 2, 1, 0, 1, 2, 3} ;
char indicators[8] = {'R','T','C','F','J','M','A','N'};

char* solution(const char* survey[], size_t survey_len, int choices[], size_t choices_len) {
    char* answer = (char*)malloc(4+1);
    int my_score[8] = {0,};
    int choice = 0;
    char category = '\0';
    int pos = 0;
   
    memset(answer, 0x00, 4+1);
    
    for(int i = 0; i < choices_len; i++)
    {
        if((choice = choices[i]) == 4) continue;
        printf("choice[%d]\n",indicators_score[choice-1]);
        category = choice < 4 ? survey[i][0] : survey[i][1];
        switch(category)
        {
            case 'R':
                my_score[0] += indicators_score[choice-1];
                break;
            case 'T':
                my_score[1] += indicators_score[choice-1];
                break;
            case 'C':
                my_score[2] += indicators_score[choice-1];
                break;
            case 'F':
                my_score[3] += indicators_score[choice-1];
                break;
            case 'J':
                my_score[4] += indicators_score[choice-1];
                break;
            case 'M':
                my_score[5] += indicators_score[choice-1];
                break;
            case 'A':
                my_score[6] += indicators_score[choice-1];
                break;
            case 'N':
                my_score[7] += indicators_score[choice-1];
                break;
        }
        
    }
    
    for(int i = 0; i < 8; i+=2){
        answer[pos++] = my_score[i] < my_score[i+1]? 
                        indicators[i+1] : indicators[i];
    }
    
    
    return answer;
}

728x90
LIST