CodingTest

Programmers - 성격 유형 검사하기

취업하고싶다! 2023. 10. 24. 15:50
 

프로그래머스

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

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
  • choices의 길이 = survey의 길이
choice
1 매우 비동의
2 비동의
3 약간 비동의
4 모르겠음
5 약간 동의
6 동의
7 매우 동의

 

 

 

접근방식

처음에 로직이 생각이 안나서 하드코딩을 이용해 구현했다. 하지만 이렇게 구현하니까 코드가 100줄을 훌쩍 넘을 뿐더러 주어진 테스트 케이스 2개는 맞았지만 다른 문제들은 맞추지 못하는 문제가 생겼다.

 

처음에 작성한 코드는 다음과 같다.

s = list(map(str, input().split()))
choices = list(map(int, input().split()))

char_arr = []
score_arr = []

for i in range(len(s)):
        sep = list(s[i])
        if choices[i] == 1:
            char_arr.append(sep[0])
            score_arr.append(3)
        elif choices[i] == 2:
            char_arr.append(sep[0])
            score_arr.append(2)
        elif choices[i] == 3:
            char_arr.append(sep[0])
            score_arr.append(1)
        elif choices[i] == 4:
            continue
        elif choices[i] == 5:
            char_arr.append(sep[1])
            score_arr.append(1)
        elif choices[i] == 6:
            char_arr.append(sep[1])
            score_arr.append(2)
        else:
            char_arr.append(sep[1])
            score_arr.append(3)

winner_arr = []

for c in char_arr:
    if c == 'R' or c == 'T':
        if c == 'R':
            if 'T' in char_arr:
                r_index = char_arr.index("R")
                t_index = char_arr.index("T")
                r_score = score_arr[r_index]
                t_score = score_arr[t_index]
                if r_score >= t_score:
                    winner_arr.append("R")
                else:
                    winner_arr.append("T")
            else:
                winner_arr.append("R")
        else: # if c == 'T'
            if 'R' in char_arr:
                r_index = char_arr.index("R")
                t_index = char_arr.index("T")
                r_score = score_arr[r_index]
                t_score = score_arr[t_index]
                if r_score >= t_score:
                    winner_arr.append("R")
                else:
                    winner_arr.append("T")
            else:
                winner_arr.append("T")
    elif c == 'C' or c == 'F':
        if c == 'C':
            if 'F' in char_arr:
                c_index = char_arr.index("C")
                f_index = char_arr.index("F")
                c_score = score_arr[r_index]
                f_score = score_arr[t_index]
                if c_score >= f_score:
                    winner_arr.append("C")
                else:
                    winner_arr.append("F")
            else:
                winner_arr.append("C")
        else: 
            if 'C' in char_arr:
                c_index = char_arr.index("C")
                f_index = char_arr.index("F")
                c_score = score_arr[r_index]
                f_score = score_arr[t_index]
                if c_score >= f_score:
                    winner_arr.append("C")
                else:
                    winner_arr.append("F")
            else:
                winner_arr.append("F")
    elif c == 'J' or c == 'M':
        if c == 'J':
            if 'M' in char_arr:
                j_index = char_arr.index("J")
                m_index = char_arr.index("M")
                j_score = score_arr[j_index]
                m_score = score_arr[j_index]
                if j_score >= m_score:
                    winner_arr.append("J")
                else:
                    winner_arr.append("M")
            else:
                winner_arr.append("J")
        else:
            if 'J' in char_arr:
                j_index = char_arr.index("J")
                m_index = char_arr.index("M")
                j_score = score_arr[j_index]
                m_score = score_arr[m_index]
                if j_score >= m_score:
                    winner_arr.append("J")
                else:
                    winner_arr.append("M")
            else:
                winner_arr.append("M")
    elif c == 'A' or c == 'N':
        if c == 'A':
            if 'N' in char_arr:
                a_index = char_arr.index("A")
                n_index = char_arr.index("N")
                a_score = score_arr[a_index]
                n_score = score_arr[n_index]
                if a_score >= n_score:
                    winner_arr.append("A")
                else:
                    winner_arr.append("N")
            else:
                winner_arr.append("A")
        else:
            if 'A' in char_arr:
                a_index = char_arr.index("A")
                n_index = char_arr.index("N")
                a_score = score_arr[a_index]
                n_score = score_arr[n_index]
                if a_score >= n_score:
                    winner_arr.append("A")
                else:
                    winner_arr.append("N")
            else:
                winner_arr.append("N")

new_arr= list(set(winner_arr)) 

# 배열 안에 원소가 없을 경우(동점이거나 나오지 않았을 때)
if 'R' not in new_arr and 'T' not in new_arr:
    new_arr.append('R')
if 'C' not in new_arr and 'F' not in new_arr:
    new_arr.append('C')
if 'J' not in new_arr and 'M' not in new_arr:
    new_arr.append('J')
if 'A' not in new_arr and 'N' not in new_arr:
    new_arr.append('A')
    
answer = []
    
if 'R' in new_arr:
    answer.append('R')
if 'T' in new_arr:
    answer.append('T')
if 'C' in new_arr:
    answer.append('C')
if 'F' in new_arr:
    answer.append('F')
if 'J' in new_arr:
    answer.append('J')
if 'M' in new_arr:
    answer.append('M')
if 'A' in new_arr:
    answer.append('A')
if 'N' in new_arr:
    answer.append('N')    
    
print(''.join(answer))

내가 생각한 로직을 설명하자면, 먼저 문자열을 받는 배열 char_arr와 점수를 받은 배열 score_arr를 각각 빈 배열로 생성한다.

입력받은 s의 길이만큼 for문을 돌리는데, 문자열이 "AN" 이런식으로 두 문자가 합쳐진 상태로 입력을 받았기에 sep =list(s[i])를 통해 문자열을 하나씩 분리해준다. 이렇게하면 sep = ['A', 'N']이 된다. 그리고 입력받은 choices 배열에서 choices[i]의 값에 따라 sep[0] 혹은 sep[1]에 score를 할당해준다. 

 

이렇게하면 입력받은 serveys와 choices들이 각각 char_arr와 score_arr에 조건에 맞는 값들이 들어가게 된다.

 

그리고 winner_arr라는 빈 배열을 생성하고 char_arr의 값들을 순회하면서 각각의 값들이 알파벳 'R', 'T', 'C', 'F', 'J', 'M', 'A', 'N' 중 어떤 것인지 확인한다. 예로 char_arr의 첫 번째 원소가 'R'이면 원소 'T'가 char_arr에 있는지 확인하고 있으면 그들의 인덱스값을 새로운 변수에 할당해주고 인덱스값으로 그들의 점수를 확인하는 변수 또한 생성해준다. 그 후 크기를 비교해 높은 값을 가진 원소를 winner_arr에 할당해준다.

 

이런 방식으로 winner_arr에 값을 다 할당해준 후, 

new_arr = list(set(winner_arr))를 통해 중복된 값이 있는 경우 제거해준다. 

 

그리고 문제를 보면 1번 지표의 2값들 중 1개, 2번 지표의 2값들 중 1개, 3번 지표의 2값들 중 1개, 4번 지표의 2값들 중 1개를 뽑아서 4개로 이뤄진 문자열을 만드는 것인데 new_arr에는 이 원소들이 다 없을 수도 있다. servey 배열에 해당 원소들의 값들이 들어가지 않았으면 비교 자체를 안하므로 arr에 들어가있을 수 없는 것이다.

 

점수가 같은 경우는 알파벳 순서가 빠른 원소를 넣어주는 작업은 위의 for문에서 처리해줬으므로 이제 점수가 아예 없는 경우 알파벳 순서가 빠른 원소를 넣어주는 작업을 해야한다. 

지표의 넘버가 같은 것들끼리 비교해서(ex: 'R'과 'T' 모두 new_arr에 없으면 R을 new_arr에 할당) 각각의 지표마다 if문을 돌면서 원소가 없는경우 new_arr에 원소를 할당해준다.

 

그리고 마지막 문제인데, 이렇게 할당했다 하더라도 문제에서 원하는 답처럼 1번지표의 2값들 중 하나가 문자열의 제일 처음에, 2번지표의 2값들 중 하나가 문자열의 2번째에, 3번지표의 2값들 중 하나가 문자열의 3번째에, 4번지표의 2값들 중 하나가 문자열의 마지막에 오는 처리가 되지 않았다.

 

이 문제를 해결하기 위해 마지막으로 answer이라는 빈 배열을 생성해줬다.

new_arr에는 1, 2, 3, 4번 지표의 2값 중 하나의 값들이 들어가있는 상태다.

if 'R' in new_arr:
    answer.append('R')
if 'T' in new_arr:
    answer.append('T')
if 'C' in new_arr:
    answer.append('C')
if 'F' in new_arr:
    answer.append('F')
if 'J' in new_arr:
    answer.append('J')
if 'M' in new_arr:
    answer.append('M')
if 'A' in new_arr:
    answer.append('A')
if 'N' in new_arr:
    answer.append('N')

이 코드를 통해 answer 배열에 순서대로 원소를 할당해주었다.

 

이러한 코드를 통해 푼 결과, 아래 사진처럼 실패한 tc 경우가 너무 많았다.

 

원래 문제를 보면 항상 어떻게 풀지 적으면서 로직을 다 정해놓고 로직을 찾고 문제를 푸는데 새벽에 풀기도했고 하드코딩으로 풀어보고싶어서 풀어봤는데 틀려서 다시 새롭게 생각했다.

 

사실 문제를 처음 봤을 때 딕셔너리를 쓰면 해결할 수 있을 것 같다고 생각했는데 딕셔너리를 제대로 써본 적이 없어서 잘 사용을 못해 문제풀이에 적용을 안했었는데 답안을 찾아보니 딕셔너리를 사용해서 푸는 문제였다.

 

 

코드

def solution(survey, choices):
    score_dict = {'R' : 0, 'T' : 0, 'C' : 0, 'F' : 0, 'J': 0, 'M' : 0, 'A' : 0, 'N' : 0}
    answer = ''
    for i in range(len(choices)):
        if choices[i] >= 5:
            score_dict[survey[i][1]] += choices[i]-4
        elif choices[i] <=3:
            score_dict[survey[i][0]] += 4-choices[i]

    score_values = list(score_dict.values())
    score_keys = list(score_dict.keys())

    for j in range(0,7,2):
        if score_values[j] >= score_values[j+1]:
            answer += score_keys[j]
        else:
            answer += score_keys[j+1]

    return answer

survey = ["AN", "CF", "MJ", "RT", "NA"]
choices = [5, 3, 2, 7, 5]
result = solution(survey, choices)
print(result)

score_dict를 딕셔너리 형식으로 선언하고 각 원소들에 0점을 초기에 할당해준다.

choices의 점수가 5점이면 받은 문자열 중 뒷 원소에 1점을, 6점이면 2점, 7점이면 3점을 추가하고,

3점이면 앞 원소에 1점을, 2점이면 2점을, 1점이면 3점을 추가하고 choices의 점수가 4점이면 어떠한 동작도 하지 않는다.

이는 choices의 값이 5보다 크거나 같을 경우 choices - 4를 통해, 3보다 작거나 같은 경우 4 - choices를 통해 구현할 수 있다.

 

입력받은 choices의 길이만큼 for문을 돌면서 choices[i] 값이 5보다 크거나 같으면 score_dict[servey[i][1]] += choices[i] - 4를 통해 점수를 더해주고 3보다 작거나 같으면 score_dict[servey[i][0]] += 4- choices[i]를 통해 점수를 더해준다.

 

그리고 딕셔너리로 되어있는 배열을 values(), keys() 를 통해 키와 밸류를 구분한 리스트를 새로 생성해준다.

 

그리고 초기에 score_dict를 R, T, C, F, J, M, A, N 이 순서대로 정의했기에 scores_keys = ['R', 'T', 'C', 'F', 'J', M', 'A', 'N']이 된다.

R, T 중 하나, C, F 중 하나, J, M 중 하나, A, N 중 하나를 뽑으면 되므로 for문을 간격을 2로 7까지 돌면서 각각의 value값을 비교해서 높은 값을 answer에 key로 더해준다. 

 

 

 

회고

딕셔너리를 잘 알고 있었으면 금방 풀 수 있었을 것 같은데 잘 몰랐기에 접근조차 안하려했던 것이 문제였던 것 같다.

문법을 더 탄탄하게 공부해야겠다....!