(프로그래머스 72412) 순위 검색

ps  · 6 mins read

이해

  • 카카오 회사에 지원한 지원자들 정보를 담은 배열 info와 문의조건이 담긴 배열 query가 매개변수로 주어진다.
  • info 배열
    • info 배열의 각 원소의 값은 “개발언어 직군 경력 소울푸드 점수” 형식이다.
    • 개발언어는 cpp, java, python 중 하나
    • 직군은 backend, frontend 중 하나
    • 경력은 junior, senior 중 하나
    • 소울푸드는 chicken, pizza 중 하나
    • 점수는 코딩테스트 점수
  • query 배열
    • query 배열의 각 원소의 값은 “[조건] X” 형식이다.
    • [조건]은 “개발언어 and 직군 and 경력 and 소울푸드” 형식이다.
    • 개발언어는 cpp, java, python, - 중 하나
    • 직군은 backend, frontend, - 중 하나
    • 경력은 junior, senior, - 중 하나
    • 소울푸드는 chicken, pizza, - 중 하나
    • ’-‘는 해당 조건을 고려하지 않겠다는 의미이다.
    • X는 코딩테스트 점수를 의미하고, 해당 조건을 만족한는 지원자 중 코딩테스트 점수가 X점 이상인 사람이 모두 몇 명인 지를 의미한다.
  • 각 문의조건에 해당하는 사람들의 숫자를 순서대로 배열에 담아 return하라.

계획

  • 딕셔너리 4개를 선언한다.
    • language 딕셔너리: 언어: {지원자1, 지원자3} 형태로 key: value를 저장한다. 예시) “python”: {1, 3}
    • part 딕셔너리: 직군: {지원자2, 지원자3} 형태로 key: value를 저장한다. 예시) “frontend”: {0, 1}
    • term 딕셔너리: 경력: {지원자1} 형태로 key: value를 저장한다. 예시) “junior”: {1}
    • soulfood 딕셔너리: 소울푸드: {지원자4, 지원자5} 형태로 key: value를 저장한다. 예시) “chicken”: {4, 5}
  • 지원자들의 코딩테스트 점수를 나타내는 score 배열을 선언한다.
  • 4개의 딕셔너리를 가지고 각 query의 조건을 만족시키는 지원자들의 번호를 원소로 가지는 집합을 구한다.
    • 예시) language[“python”] ∩ part[“frontend”] = {1, 3} ∩ {0, 1} = {1}
  • 조건을 만족시키는 지원자 마다 코딩 테스트 점수를 확인하여 X점 이상인 경우에 카운트
  • info 길이: N, query 배열 길이: M → 시간 복잡도: O(N*M)

정확성 테스트는 전부 통과했지만 효율성 테스트를 통과하지 못했다.

실행

def solution(info, query):
    language = {"cpp": set(), "java": set(),"python": set(), "-": set(range(len(info)))}
    part = {"backend": set(), "frontend": set(), "-": set(range(len(info)))}
    term = {"junior": set(), "senior": set(), "-": set(range(len(info)))}
    soulfood = {"chicken": set(), "pizza": set(), "-": set(range(len(info)))}
    score = []
    for i, s in enumerate(info):
        l, p, t, so, sc = s.split(" ")

        language[l].add(i)
        part[p].add(i)
        term[t].add(i)
        soulfood[so].add(i)
        score.append(sc)
    
    answer = []
    for q in query:
        
        temp = q.split(" ")
        l, p, t, so, sc = temp[0], temp[2], temp[4], temp[6], temp[7] 

        intersect = language[l] & part[p] & term[t] & soulfood[so]
        answer.append(len([i for i in intersect if int(score[i]) >= int(sc)]))
    return answer  

개선

  • 지원자들을 그룹별로 분류한다.
    • 예를 들어, “java backend junior pizza 150” 지원자의 경우 다음 아래의 16개의 그룹에 속하게 된다.
    • “java backend junior pizza”
    • “– backend junior pizza”
    • “java – junior pizza 150”
    • “– – – -“
  • 딕셔너리를 선언하여 그룹: score1, score2, … 형태로 key: value를 저장한다.
  • 각 쿼리의 조건을 key값으로 하여 해당 조건을 만족하는 지원자들의 점수들을 담은 배열을 가져와서 이분 탐색을 진행하여 X 이상인 점수의 개수를 센다.
  • info 길이: N, query 배열 길이: M → 시간 복잡도: O(M * logN)
def binary_search_opt(arr, x):
    if x > arr[-1]: 
        return len(arr)
    start = 0
    end = len(arr) - 1
    result = int(1e9)
    while start <= end:
        mid = (start + end) // 2
        if arr[mid] >= x:
            result = min(mid, result)
            end = mid - 1
        else:
            start = mid + 1
    return result

def solution(info, query):
    group = dict()

    for _info in info:
        l, p, t, so, sc = _info.split(" ")
        
        for i in ['-', l]:
            for j in ['-', p]:
                for k in ['-', t]:
                    for w in ['-', so]:
                        key = i+j+k+w
                        if key not in group:
                            group[key] = [int(sc)]
                        else:
                            group[key].append(int(sc))

    for key in group:
        group[key].sort()
    
    answer = []
    for q in query:
        temp = q.replace(" and ", "").split(" ")
        cond = "".join(temp[:-1])
        score = int(temp[-1])
        if cond not in group:
            answer.append(0)
        else:
            answer.append(len(group[cond]) - binary_search_opt(group[cond], score))
    
    return answer

회고

  • 문제를 풀면서 효율성 테스트를 통과하지 못할 거라고 생각했는데 역시나 시간초과가 떴다.
  • 어려웠지만 계획을 구체적으로 짜서 깔끔하게 잘 푼 것 같았는데 아쉬웠다.
  • 이분 탐색 유형을 접한 지 오래돼서 효율성 테스트를 통과할 만한 풀이를 떠올리지 못한 것 같다.
  • level2 문제지만 카카오 문제는 역시 까다롭다.