[프로그래머스 Level1] kakao 기출 문제

Wonjun·2022년 6월 25일
0
post-thumbnail

📝 [1차] 비밀지도

문제 설명

2018 KAKAO BLIND RECRUITMENT > [1차] 비밀지도

해결 방법

tmp1, tmp2 벡터를 선언하고 arr1, arr2의 숫자들을 이진법 변환해서 각각 tmp1, tmp2에 push_back 한다. 이진법 변환 후 남은 공간은 0으로 채운다. string map 변수를 선언하고 이진법이 거꾸로 들어갔기 때문에 뒤에서부터 tmp1, tmp2를 참조해서 둘 다 1이면 '#', 둘 다 0이면 공백' ', 그 이외는 '#'으로 map을 구성한 뒤 answr에 push_back 한다.

💻소스코드

#include <string>
#include <vector>

using namespace std;

vector<string> solution(int n, vector<int> arr1, vector<int> arr2) {
    vector<string> answer;
    for (int i = 0; i < arr1.size(); i++) {
        int reps = n;
        vector<int> tmp1, tmp2;
        while (reps > 0) {
            if (arr1[i] == 0)
                tmp1.push_back(0);
            else {
                tmp1.push_back(arr1[i] % 2);
                arr1[i] /= 2;
            }
            if (arr2[i] == 0) 
                tmp2.push_back(0);
            else {
                tmp2.push_back(arr2[i] % 2);
                arr2[i] /= 2;
            }
            reps--;
        }
        int idx = tmp1.size() - 1;
        string map = "";
        while (idx > -1) {
            if (tmp1[idx] == 1 && tmp2[idx] == 1)
                map += "#";
            else if (tmp1[idx] == 0 && tmp2[idx] == 0)
                map += " ";
            else
                map += "#";
            idx--;
        }
        answer.push_back(map);
    }
    return answer;
}

📝 [1차] 다트게임

문제 설명

2018 KAKAO BLIND RECRUITMENT > [1차] 다트게임

해결 방법

if, else if 도배하는 방법밖엔 떠오르지 않았다. 스타상*의 역할 때문에 문제가 더 까다롭게 느껴졌다. tmp 변수를 활용하여 스타상*을 처리했다. score는 해당 점수, tmp는 바로 전에 얻은 점수를 저장한다. 이외에는 문제 조건을 그대로 가져왔다.

💻소스코드

#include <string>
#include <vector>
#include <cmath>

using namespace std;

int solution(string dartResult) {
    int answer = 0;
    int score = 0;  // 해당 점수
    int tmp = 0;    // 바로 전에 얻은 점수
    for (int i = 0; i < dartResult.size(); i++) {
        if ('0' <= dartResult[i] && dartResult[i] <= '9') {
            tmp = score;    // 바로 전에 얻은 점수를 저장
            if (dartResult[i + 1] == '0') {
                score = 10;
                i++;
            }
            else
                score = dartResult[i] - '0';
        }
        // 'S'일 경우 score^1이므로 변화 X
        else if (dartResult[i] == 'S' || dartResult[i] == 'D' || dartResult[i] == 'T') {
            if (dartResult[i] == 'D')
                score = pow(score, 2);
            else if (dartResult[i] == 'T')
                score = pow(score, 3);
            
            if (dartResult[i + 1] == '*') {     // 스타상일 경우 해당 점수와 바로 전에 얻은 점수를 각 2배
                answer -= tmp;
                tmp *= 2;
                score *= 2;
                answer += tmp;
                i++;
            }
            else if (dartResult[i + 1] == '#') {    // 아차상일 경우 해당점수만 * -1
                score *= -1;    
                i++;
            }
            answer += score;
        }
    }
    return answer;
}

📝 로또의 최고 순위와 최저 순위

문제 설명

2021 Dev-Matching: 웹 백엔드 개발자(상반기) > 로또의 최고 순위와 최저 순위

해결 방법

win_nums 배열의 요소와 일치하는 lottos 배열 요소의 개수(cnt)를 algorithm 헤더의 find 함수를 이용해서 센다. 이중 for 문으로도 셀 수 있다. 일치하는 로또 번호가 2개 이상일 때부터 유의미한 rank 변동이 발생하므로 1개 번호만 일치할 경우 6위를 유지한다. 0을 고려하지 않고 순수 일치하는 번호만 봤으므로 최저 순위를 구한 것이다. 최고 순위를 구하기 위해 모든 0을 일치하는 숫자로 가정한다. lottos 배열의 요소에 접근하면서 0을 찾는다. 이 때, 일치하는 번호가 아예 없었다면(if cnt == 0) 0이 1개일 때는 순위 변동이 없다.(rank = 6) 그렇지 않다면 0의 개수만큼 순위가 올라간다. return 값이 [최고 순위, 최저 순위]이므로 insert를 이용해서 rank를 answer 배열의 맨 앞에 넣어준다.

💻소스코드

#include <string>
#include <vector>
#include <algorithm>

using namespace std;

vector<int> solution(vector<int> lottos, vector<int> win_nums) {
    vector<int> answer;
    int cnt = 0;
    int rank = 6;
    // 일치하는 번호의 갯수 세기
    for (int i = 0; i < win_nums.size(); i++) {
        if (find(lottos.begin(), lottos.end(), win_nums[i]) != lottos.end()) {   
            cnt++;
        }
    }
    // 최저 순위
    if (cnt > 1)    // 1개 번호만 일치할 경우 6위 유지
        rank -= (cnt - 1);
    answer.push_back(rank); 
    
    // 최고 순위를 구하기 위해 0을 일치하는 숫자로 판단
    for (int i = 0; i <lottos.size(); i++) {
        if (lottos[i] == 0){
            if (cnt == 0){  // 일치하는 번호가 없었을 때, 0을 일치하는 숫자로 판단하더라도 0이 1개일 때 순위는 6위
                rank = 6;
                cnt++;
            }
            else
                rank -= 1;
        }
    }
    answer.insert(answer.begin(), rank);    // 최고 순위를 앞에 삽입
    return answer;
}

📝 신규 아이디 추천

문제 설명

2021 KAKAO BLIND RECRUITMENT > 신규 아이디 추천

해결 방법

문제에 제시된 단계별 조건들을 순차적으로 코딩했다.

  • 1단계: 모든 대문자를 소문자로 치환

tolower 함수를 사용했다.

  • 2단계: 특정한 문자를 제외한 모든 문자를 제거

소문자, 숫자, 빼기(-), 밑줄(_), 마침표(.) 을 제외한 문자들을 공백(' ') 으로 치환하고, find, erase 함수를 통해 제거했다.

  • 3단계: 마침표(.) 가 2번 이상 연속된 부분을 하나의 마침표(.)로 치환

find, replace 함수를 사용하여 치환했다.

  • 4단계: 마침표(.)가 처음이나 끝에 위치한다면 제거

if문을 사용해서 제거했다.

  • 5단계: 빈 문자열이라면, new_id에 "a"를 대입

마찬가지로 if문과 empty 함수를 사용해서 대입했다.

  • 6단계: 길이가 16자 이상이면, new_id의 첫 15개의 문자를 제외한 나머지 문자들을 모두 제거, 만약 제거 후 마침표(.)가 new_id의 끝에 위치한다면 끝에 위치한 마침표(.) 문자를 제거

if문과 erase 함수 사용했다.

  • 7단계: new_id의 길이가 2자 이하라면, new_id의 마지막 문자를 new_id의 길이가 3이 될 때까지 반복해서 끝에 붙인다

temp라는 새로운 int 변수를 선언해서 new_id의 길이를 넣어두고 for문으로 문자를 붙여주었다. 만약 new_id의 길이를 바로 참조할 경우 오류가 발생한다.

💻소스코드

#include <string>
#include <vector>

using namespace std;

string solution(string new_id) {
    string answer = "";
    int idx;
    // step 1
    for (int i = 0; i < new_id.length(); i++){
        if ('A' <= new_id[i] && new_id[i] <= 'Z')
            new_id[i] = tolower(new_id[i]);
    }
    
    // step 2
    for (int i = 0; i < new_id.length(); i++){
        if (!('a' <= new_id[i] && new_id[i] <= 'z') && !('0' <= new_id[i] && new_id[i] <= '9') &&
            new_id[i] != '-' && new_id[i] != '_' && new_id[i] != '.')
            new_id[i] = ' ';
    }
    while (1){
        idx = new_id.find(" ");
        if (idx == string::npos)
            break;
        new_id.erase(idx, 1);
    }
    
    // step 3
    while (1){
        idx = new_id.find("..");
        if (idx == string::npos)
            break;
        new_id.replace(idx, 2, ".");
    }
    
    // step 4
    if (new_id[0] == '.')
        new_id.erase(0, 1);
    if (new_id[new_id.length() - 1] == '.')
        new_id.erase(new_id.length() - 1, 1);
    
    // step 5
    if (new_id.empty())
        new_id = "a";
    
    // step 6
    if (new_id.length() >= 16)
        new_id.erase(15, new_id.length() - 15);
    if (new_id[new_id.length() - 1] == '.')
        new_id.erase(new_id.length() - 1, 1);
    
    // step 7
    int temp = new_id.length();
    if (new_id.length() <= 2){
        for (int i = 0; i < 3 - temp; i++)
            new_id += new_id[new_id.length() - 1];
    }
    answer = new_id;
    return answer;
}

📝 숫자 문자열과 영단어

문제 설명

2021 카카오 채용연계형 인턴십 > 숫자 문자열과 영단어

해결 방법

주어진 string에서 영어로 표기된 수들을 0 ~ 9의 10진수로 바꾸는 문제다. string s 내에서 영단어 숫자를 find 함수를 사용해서 찾고, replace 함수를 사용해서 원래 숫자로 바꾸었다. 바꾼 결과물은 string이므로 stoi 함수를 사용해서 int로 바꿔주고 return했다.
find 함수는 찾고자하는 str이 없을 때 string::npos를 return한다. 그래서 무한 루프에 찾고자하는 영단어가 없다면(string::npos를 반환) break를 걸어 빠져나오도록 했다.

💻소스코드

#include <string>
#include <vector>

using namespace std;

int solution(string s) {
    int answer = 0;
    vector<string> num = { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" };
    vector<string> digit = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" };
    int idx;
    for (int i = 0; i < num.size(); i++) {
        while (1) {
            idx = s.find(num[i]);
            if (idx == string::npos)
                break;
            s.replace(idx, num[i].length(), digit[i]);
        }
    }
    answer = stoi(s);
    return answer;
}

📝 크레인 인형뽑기 게임

문제 설명

2019 카카오 개발자 겨울 인턴십 > 크레인 인형뽑기 게임

해결 방법

크레인을 통해 인형들을 뽑아서 stack 배열에 차곡차곡 넣는다. 모양이 같은 인형이 겹칠 때마다 사라지게 하는 것이 아니라 우선 넣고 본다. moves 배열의 크기만큼 다 넣고 난 후, stack 배열을 처음부터 돌면서 앞, 바로 뒤가 같은 모양의 인형이면(같은 숫자면) stack에서 지우고 answer에 2를 더해준다. 다시 stack의 처음으로 돌아가 겹친 인형이 없을 때까지 반복한다.

  • stack.size()가 0일 때 예외처리를 안해줬더니 하나의 테스트 케이스에서 segmentation fault가 떴다.

💻소스코드

#include <string>
#include <vector>

using namespace std;

int solution(vector<vector<int>> board, vector<int> moves) {
    int answer = 0;
    vector<int> stack;
    // 0 0 0 0 0
    // 0 0 1 0 3
    // 0 2 5 0 1
    // 4 2 4 4 2
    // 3 5 1 3 1
    for (int i = 0; i < moves.size(); i++) {
        for (int j = 0; j < board[moves[i] - 1].size(); j++) {  // 위에서부터
            if (board[j][moves[i] - 1] != 0) {
                stack.push_back(board[j][moves[i] - 1]);    // 인형을 stack에 넣는다
                board[j][moves[i] - 1] = 0;     // 다음 크레인이 왔을 때 중복해서 인형을 넣지 않기 위해 0 할당
                break;
            }
        }
    }
    int idx = 0;
    while (idx != stack.size() - 1) {
        if (stack.size() == 0)
            break;
        if (stack[idx] == stack[idx + 1]) { // 같은 모양의 인형이면,
            answer += 2;
            stack.erase(stack.begin() + idx, stack.begin() + idx + 2);  // 두 인형을 사라지게 한다.
            idx = -1;   // 미리 stack에 인형들을 넣어놨기 때문에 처음부터 다시 찾기 위해
        }
        idx++;
    }
    return answer;
}

📝 키패드 누르기

문제 설명

2020 카카오 인턴십 > 키패드 누르기

해결 방법

숫자 1,4,7의 경우 항상 왼손으로 누르고 3,6,9의 경우 항상 오른손으로 누른다. 다음 누를 번호와 왼손, 오른손과의 거리 차이를 구하기 위해 *, 0, #은 각각 10, 11, 12로 대체한다. left_hand와 right_hand 변수를 선언하여 각각 왼손과 오른손이 누른 번호의 값을 저장한다. 2, 5, 8, 0 숫자를 눌렀을 땐 왼손, 오른손과 숫자 사이의 거리 계산을 해주어야 하므로 dis_l, dis_r 변수를 새로 선언하고 거리 값으로 초기화한다. 거리는 (누를 번호 - 왼손, 오른손이 위치한 번호) / 3 + (누를 번호 - 왼손, 오른손이 위치한 번호) % 3 로 구할 수 있다. 두 손과의 거리가 같을 땐 매개변수 hand로 받아온 인자를 확인해서 left면 왼손으로, right면 오른손으로 누른다. 왼손 거리가 더 멸면, 오른손으로 누르고, 오른손 거리가 더 멸면, 왼손으로 누른다.

💻소스코드

#include <string>
#include <vector>
#include <cmath>
using namespace std;

string solution(vector<int> numbers, string hand) {
    string answer = "";
    int left_hand = 10, right_hand = 12;    // *, #
    for (int i = 0; i < numbers.size(); i++) {
        if (numbers[i] == 1 || numbers[i] == 4 || numbers[i] == 7) {    // 1, 4, 7 입력
            answer += "L";
            left_hand = numbers[i];
        }
        else if (numbers[i] == 3 || numbers[i] == 6 || numbers[i] == 9) {   // 3, 6, 9 입력
            answer += "R";
            right_hand = numbers[i];
        }
        else {  // 2, 5, 8, 0 입력
            if (numbers[i] == 0)
                numbers[i] = 11;
            
            // 왼손, 오른손과 누를 번호의 거리
            int dis_l = abs(numbers[i] - left_hand) / 3 + abs(numbers[i] - left_hand) % 3;
            int dis_r = abs(numbers[i] - right_hand) / 3 + abs(numbers[i] - right_hand) % 3;
            if (dis_l == dis_r) {   // 왼손, 오른손 거리가 같을 때
                if (hand == "right") {
                    answer += "R";
                    right_hand = numbers[i];
                }
                else {
                    answer += "L";
                    left_hand = numbers[i];
                }
            }
            else if (dis_l > dis_r) {   // 왼손 거리가 더 멀면
                answer += "R";
                right_hand = numbers[i];
            }
            else {  // 오른손 거리가 더 멀면
                answer += "L";
                left_hand = numbers[i];
            }
        }
    }
    return answer;
}

📝 실패율

문제 설명

2019 KAKAO BLIND RECRUITMENT > 실패율

해결 방법

1단계부터 N단계까지 차례대로 실패율을 구해서 fail 배열에 push_back 한다. 실패율을 구할 때 이중 for문을 사용했다. # 주의해야 할 점은 실패율 구할 때 실수형으로 형변환을 해주어야 한다. 안해주면 0만 나옴. #
pair<int, double>를 사용해서 단계별로 실패율을 묶어서 push_back 한다. 스테이지에 도달한 플레이어의 수total가 0일 경우 divide by 0 케이스기 때문에 total = 1을 해서 예외처리를 했다. 어차피 실패율이 0인 것은 같다. 우선적으로 실패율 기준 내림차순 정렬을 하는데, 실패율이 같을 경우 스테이지를 기준으로 오름차순 정렬한다. 이를 위해 cmp 함수를 따로 구현했다. 마지막으로 sort 함수에 구현한 cmp 함수를 인자로 받아 문제 조건에 맞게 정렬이 된 fail.first(stages)를 answer 배열에 push_back 한다.

💻소스코드

#include <string>
#include <vector>
#include <algorithm>

using namespace std;

bool cmp(pair<int, double>& a, pair<int, double>& b) {
	if (a.second == b.second)       // 실패율이 같다면
        return a.first < b.first;   // 스테이지를 오름차순으로 정렬
	return a.second > b.second;     // 실패율의 내림차순 정렬
}

vector<int> solution(int N, vector<int> stages) {
    vector<int> answer;
    vector<pair<int, double>> fail;
    for (int i = 1; i <= N; i++) {
        int not_clear = 0;  // 스테이지에 도달했으나 아직 클리어하지 못한 플레이어의 수
        int total = 0;      // 스테이지에 도달한 플레이어 수
        for (int j = 0; j < stages.size(); j++) {
            if (stages[j] >= i) {
                total++;
                if (stages[j] == i)
                    not_clear++;
            }
        }
        if (total == 0) // divide by 0, 예외처리
            total = 1;
        fail.push_back({i, (double)not_clear / total});    // 실패율
    }
    sort(fail.begin(), fail.end(), cmp);
    for (auto it : fail) {
        answer.push_back(it.first);
    }
    return answer;
}

📝 신고 결과 받기

문제 설명

2022 KAKAO BLIND RECRUITMENT > 신고 결과 받기

해결 방법

유저별 신고당한 횟수를 담을 map<string, int> report_cnt을 선언
유저별 중복을 제거(set)하여 신고한 타 유저 map<string, set<string>> report_map을 선언한다.
한 유저를 여러 번 신고할 수도 있지만, 동일한 유저에 대한 신고 횟수는 1회로 처리된다는 조건이 있기 때문이다.
report 벡터를 참조하여 공백기준(' ')으로 앞의 문자열은 신고한 사람, 뒤의 문자열은 신고 당한 사람으로 parsing해서 report_map에 insert한다.
id_list에 담긴 유저 순서대로 k회 이상 신고당한 사람을 세서 결과 메일 수를 증가시켜주고 push_back한다.

💻소스코드

#include <string>
#include <vector>
#include <set>
#include <map>

using namespace std;

vector<int> solution(vector<string> id_list, vector<string> report, int k) {
    vector<int> answer; // 유저별 받은 결과 메일 수
    map <string, int> report_cnt; // 유저별 신고당한 횟수
    map <string, set<string>> report_map;   // 유저별 신고한 타 유저 map, 중복 제거
    for (string s : report) {
        int bnk = s.find(' ');  // 공백기준 문자열 parsing
        string first = s.substr(0, bnk);    // 신고한 사람
        string second = s.substr(bnk);      // 신고 당한 사람
        
        // first가 second를 신고한 이력이 없다면
        if (report_map[first].find(second) == report_map[first].end()) {
            report_cnt[second]++;   // 신고횟수 늘려주고
            report_map[first].insert(second);   // report_map에 추가
        }
    }
    
    for (string s : id_list) {
        int result = 0;
        // k회 이상 신고 당한 사람 존재
        for (string str : report_map[s]) {
            if (report_cnt[str] >= k)
                result++;
        }
        answer.push_back(result);
    }
    return answer;
}

profile
알고리즘

0개의 댓글