[프로그래머스] 230814-16 달리기 경주

예슬·2023년 8월 16일
0

Algorithm study

목록 보기
7/11
post-thumbnail

문제 설명

얀에서는 매년 달리기 경주가 열립니다. 해설진들은 선수들이 자기 바로 앞의 선수를 추월할 때 추월한 선수의 이름을 부릅니다. 예를 들어 1등부터 3등까지 "mumu", "soe", "poe" 선수들이 순서대로 달리고 있을 때, 해설진이 "soe"선수를 불렀다면 2등인 "soe" 선수가 1등인 "mumu" 선수를 추월했다는 것입니다. 즉 "soe" 선수가 1등, "mumu" 선수가 2등으로 바뀝니다.

선수들의 이름이 1등부터 현재 등수 순서대로 담긴 문자열 배열 players와 해설진이 부른 이름을 담은 문자열 배열 callings가 매개변수로 주어질 때, 경주가 끝났을 때 선수들의 이름을 1등부터 등수 순서대로 배열에 담아 return 하는 solution 함수를 완성해주세요.

제한사항

5 ≤ players의 길이 ≤ 50,000
players[i]는 i번째 선수의 이름을 의미합니다.
players의 원소들은 알파벳 소문자로만 이루어져 있습니다.
players에는 중복된 값이 들어가 있지 않습니다.
3 ≤ players[i]의 길이 ≤ 10
2 ≤ callings의 길이 ≤ 1,000,000
callings는 players의 원소들로만 이루어져 있습니다.
경주 진행중 1등인 선수의 이름은 불리지 않습니다.

입출력 예

players callings result
["mumu", "soe", "poe", "kai", "mine"]["kai", "kai", "mine", "mine"] ["mumu", "kai", "mine", "soe", "poe"]
입출력 예 설명
입출력 예 #1

4등인 "kai" 선수가 2번 추월하여 2등이 되고 앞서 3등, 2등인 "poe", "soe" 선수는 4등, 3등이 됩니다. 5등인 "mine" 선수가 2번 추월하여 4등, 3등인 "poe", "soe" 선수가 5등, 4등이 되고 경주가 끝납니다. 1등부터 배열에 담으면 ["mumu", "kai", "mine", "soe", "poe"]이 됩니다.

풀이 방법

처음에는 players 배열에서 callings[i]의 인덱스를 찾아 앞자리 배열 값과 교체해주면 된다는 간단한 생각을 했었다.
그런데 이 문제에서 핵심은 버블 정렬이 아닌가보다. 대부분의 테스트에서 통과는 했으나 몇 개의 테스트 케이스는 시간 초과 로 실패 해 버렸다.

아래는 배열&버블 정렬로 시도 했던 코드

import java.util.Arrays;
import java.util.List;
import java.util.ArrayList;

class Solution {
    public String[] solution(String[] players, String[] callings) {
        String[] answer = {};
        
        for(int i=0; i<callings.length; i++){
            int idx = Arrays.asList(players).indexOf(callings[i]);
            // 배열 index 앞자리와 자리 교체
            String str = players[idx-1];
            players[idx-1] = players[idx];
            players[idx] = str;
        }
        
        return players;
    }
}


프로그래머스의 질문하기 부분을 몇 개 읽어본 결과 Map을 사용하면 된다는 것을 알았다.
코드는 좀 더 복잡해 보이지만, 코드의 실제 복잡도는 낮나보다.

두번째 시도

import java.util.*;

class Solution {
    public String[] solution(String[] players, String[] callings) {
        int key = -1;
        String value;
        
        // map 만들기
        HashMap<Integer, String> map = new HashMap<Integer, String>();
        // map에 값 넣기(순서, 이름)
        for(int i=0; i<players.length; i++){
            map.put(i+1, players[i]);
        }
        
        // callings의 길이만큼 검사
        for(int i=0; i<callings.length; i++){
            // callings[i]의 값을 map에서 검색(결과는 순서(key))
            for(Map.Entry<Integer, String> ent: map.entrySet()){
                if(ent.getValue().equals(callings[i])){
                    key = ent.getKey();
                    break;
                }
            }
            
            // 해당하는 (key-1, value) 의 자리를 찾고 자리를 교체
            // map.put()의 키가 존재했을 때 값을 덮어쓰기 한다는 성질을 이용
            map.put(key, map.get(key-1));
            map.put(key-1, callings[i]);
            
        }
        // answer 값 만들기
        String[] answer = new String[map.size()];
        for(int i=0; i<map.size(); i++){
            answer[i] = map.get(i+1);
        }
        
        return answer;
    }
}

는 실패~!!

뭐지? 아까보다 더 느리다.
생각해보니까 이렇게 사용해버리면 map을 사용하는 의미가 없다. ㅎㅎ;
iterator을 사용하기 때문에...
map의 구조를 바꾸어야 한다(key는 이름, value는 이름으로.)



생각보다 푸는 데 오래 걸려 다른 사람의 풀이를 살짝 훑어봤다.
문제의 핵심은 map 하나를 만들고 그 하나에만 몰두하면 안된다는 것이었다.
(그 map 자체만을 가지고 수정하는 것이 아니라는 말이다!)
기존에 주어진 players 배열을 사용하여 value를 찾는데 사용을 하더라.
유레카.

덕분에 코드도 엄청 짧아진다.

import java.util.*;

class Solution {
    public String[] solution(String[] players, String[] callings) {
        String temp;
        int rank = -1;
        
        // map 만들기
        HashMap<String, Integer> map = new HashMap<String, Integer>();
        // map에 값 넣기(순서, 이름)
        for(int i=0; i<players.length; i++){
            map.put(players[i], i+1);
        }
        
        // callings의 길이만큼 검사
        for(int i=0; i<callings.length; i++){
            // callings[i]의 값을 map에서 검색(결과는 현재등수)
            rank = map.get(callings[i]);
            
            // rank는 기존 rank, rank-1로 바뀌어야 함
            // 그러나 배열은 0부터 시작하므로 -1씩 더 해주어야 한다!

            // players 배열 자리 교체
            temp = players[rank-1];
            players[rank-1] = players[rank-2];
            players[rank-2] = temp;
            
            // map 자리 교체
            map.put(players[rank-1], rank);
            map.put(players[rank-2], rank-1);
            
        }
        
        return players;
    }
}


해당 문제를 풀면서...

원래는 js나 c++을 사용하여 맥북 터미널에서 테스트 코드를 돌려보곤 했다.
맥북을 사용하기 때문에 java코드를 돌려보는 것에 불편함이 있었는데, 코딩테스트를 할 때는 IDE만 주고 테스트를 한다고하니... 익숙해질 필요가 있는 것 같다.
오랜만에 자바 코딩을 해보면서 까먹은 용어들이 많았다.
자동 완성이 안되니 sysout을 일일이 타자쳐야 하는 것도 불편했다.
이런 불편한 점들도 익숙해지면 괜찮아 질 것이라 생각한다. 열심히 하자 :)

profile
블로그 이사 했습니다! 🏠 ⤵

0개의 댓글