PS/Programmers

[Programmers Level2] 스킬트리(C++)

박땅콩 2022. 12. 16.
728x90

※주의※

저의 풀이가 정답은 아닙니다.

다른 코드가 더 효율적이거나 좋을 수 있습니다.

언제나 다른 사람의 코드는 참고만 하시기 바랍니다.

 

 

[문제 풀이 사이트]

 

 

 

프로그래머스

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

programmers.co.kr

 

 

[문제 설명]

 

 

선행 스킬이란 어떤 스킬을 배우기 전에 먼저 배워야 하는 스킬을 뜻합니다.

예를 들어 선행 스킬 순서가 스파크 → 라이트닝 볼트 → 썬더일때, 썬더를 배우려면 먼저 라이트닝 볼트를 배워야 하고, 라이트닝 볼트를 배우려면 먼저 스파크를 배워야 합니다.

위 순서에 없는 다른 스킬(힐링 등)은 순서에 상관없이 배울 수 있습니다. 따라서 스파크 → 힐링 → 라이트닝 볼트 → 썬더와 같은 스킬트리는 가능하지만, 썬더 → 스파크나 라이트닝 볼트 → 스파크 → 힐링 → 썬더와 같은 스킬트리는 불가능합니다.

선행 스킬 순서 skill과 유저들이 만든 스킬트리1를 담은 배열 skill_trees가 매개변수로 주어질 때, 가능한 스킬트리 개수를 return 하는 solution 함수를 작성해주세요.

 

 

[제한 사항]

 

 

  • 스킬은 알파벳 대문자로 표기하며, 모든 문자열은 알파벳 대문자로만 이루어져 있습니다.
  • 스킬 순서와 스킬트리는 문자열로 표기합니다.
    • 예를 들어, C → B → D 라면 "CBD"로 표기합니다
  • 선행 스킬 순서 skill의 길이는 1 이상 26 이하이며, 스킬은 중복해 주어지지 않습니다.
  • skill_trees는 길이 1 이상 20 이하인 배열입니다.
  • skill_trees의 원소는 스킬을 나타내는 문자열입니다.
    • skill_trees의 원소는 길이가 2 이상 26 이하인 문자열이며, 스킬이 중복해 주어지지 않습니다.

 

 

[입출력 예]

 

 

skill skill_trees return
"CBD" ["BACDE", "CBADF", "AECB", "BDA"] 2

 

 

[입출력 예 설명]

 

 

  • "BACDE": B 스킬을 배우기 전에 C 스킬을 먼저 배워야 합니다. 불가능한 스킬트립니다.
  • "CBADF": 가능한 스킬트리입니다.
  • "AECB": 가능한 스킬트리입니다.
  • "BDA": B 스킬을 배우기 전에 C 스킬을 먼저 배워야 합니다. 불가능한 스킬트리입니다.

 

 

[문제 풀이]

 

입출력 예로 문제 풀이를 설명해보도록 하겠다.

 

1. 선행 스킬의 순서기록하기 위해 map사용했다.

map의 key(char)선행 스킬value(int)스킬 순서의미한다.

 

그럼, 아래와 같이 map에 기록이 된다.

선행 스킬 순서는 'C' -> 'B' -> 'D' 순서이다.

 

2. 주어진 스킬 트리에서 가능한 스킬 트리 개수를 구해야 한다.

선행 스킬이 없는 스킬 트리는 순서에 상관 없이 스킬을 배울 수 있다.

하지만 단 1개라도 선행 스킬이 있는 스킬트리는 순서에 맞게 선행 스킬을 배워야 한다.

 

☑ 스킬트리 "BACDE"는 선행 스킬 'B', 'C', 'D' 모두 존재한다.

하지만, 2번째로 배우는 'B'스킬이 1번째로 배워야 할 'C'스킬보다 먼저 배운다.

➜ map의 find함수를 이용하여 선행 스킬(key)을 찾았다면 해당 스킬 순서와  현재 배워야 하는 순서랑 비교한다.

비교했을 때 다르다면 해당 스킬 트리는 패스한다.

➜ 이 경우엔 'C'스킬이 먼저 선행으로 배워야 하므로 "BACDE" 스킬은 배울 수 없다.

 

☑ 스킬트리 "CBADF"는 선행 스킬 'C', 'B', 'D' 모두 존재한다.

➜ map의 find함수를 이용하여 선행 스킬(key)을 찾았다면 해당 스킬 순서와  현재 배워야 하는 순서랑 비교한다.

비교했을 때 같다면 해당 스킬 트리는 가능한 스킬 트리이다.

 이 경우엔 배우는 선행 스킬 순서 또한 'C' -> 'B' -> 'D' 로 순서에 맞게 배우기 때문에 가능한 스킬 트리로 확인된다.

 

☑ 스킬트리 "AECB"는 선행 스킬 'C', "B'가 존재한다.

➜ map의 find함수를 이용하여 선행 스킬(key)을 찾았다면 해당 스킬 순서와  현재 배워야 하는 순서랑 비교한다.

비교했을 때 같다면 해당 스킬 트리는 가능한 스킬 트리이다.

➜ 배우는 선행 스킬 순서 또한 'C' -> 'B'로 순서에 맞게 배운다. 그러므로 가능한 스킬 트리로 확인된다.

 

☑ 스킬트리 "BDA"는 선행 스킬 'B'가 존재한다.

➜ map의 find함수를 이용하여 선행 스킬(key)을 찾았다면 해당 스킬 순서와  현재 배워야 하는 순서랑 비교한다.

비교했을 때 다르다면 해당 스킬 트리는 패스한다.

➜ 'B' 스킬의 경우 배우기 전에 먼저 'C' 스킬을 선행으로 배워야 하므로 "BDA" 스킬은 배울 수 없다.

 

 

그리고 나는 코드 상에서 여러 테스트 케이스로 인해 boolean 변수 2개를 사용했다.

1. 주어진 스킬 트리가 선행 스킬로만 구성된 스킬 트리인경우 또는 선행 스킬이 아예 존재하지 않는 스킬트리인 경우

2. 선행 스킬트리 순서가 맞지 않는 경우

 

 

[최종 코드]

 

 

[GitHub]

 

 

 

GitHub - SmallPeanutPark/Programmers: Study Programmers for Coding Test

Study Programmers for Coding Test. Contribute to SmallPeanutPark/Programmers development by creating an account on GitHub.

github.com

 

 

#include <string>
#include <vector>
#include <map>
#include <iostream>

using namespace std;

map<char, int> skillorder;

void setSkillOrder(string s, int len) {
    // 스킬 순서를 기록한다. 1번째부터 시작
    for(int i = 0; i < len; ++i) {
        skillorder[s[i]] = (i + 1);
    }
}

int getEnableSkillTrees(vector<string> skill_trees, int cur) {
    int gSize = skill_trees.size();
    int count = 0;
    for(int i = 0; i < gSize; ++i) {
        string s = skill_trees[i];
        int len = s.length();
        int skill_idx = 1;
        bool isfind = false;
        bool isnot = false;
        for(int j = 0; j < len; ++j) {
            if(skillorder.find(s[j]) != skillorder.end()) {
                // 스킬을 찾음 -> 순서 맞는지 확인
                isfind = true;
                if(skill_idx == skillorder[s[j]]) {
                    skill_idx += 1;
                } else {
                    isnot = true;
                    break;
                }
            } else {
                // 선행 스킬에 해당되지 않는 경우
            }
        }

        if(isfind && (!isnot)) {
            count += 1;
        }

        if(!isfind) {
            // 스킬트리가 선행스킬로 이루어지지 않은 경우
            count += 1;
        }
    }
    return count;
}

int solution(string skill, vector<string> skill_trees) {
    int len = skill.length();
    setSkillOrder(skill, len);
    int answer = getEnableSkillTrees(skill_trees, len);
    return answer;
}
728x90

댓글