코딩테스트

달리기 경주, 공원 산책 , 유연근무제

Cadi 2025. 2. 21. 02:32

코딩테스트 : 달리기 경주

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

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

using System;
using System.Collections.Generic;
using System.Linq;

public class Solution
{
    public string[] solution(string[] players, string[] callings)
    {
        Dictionary<string, int> playersNameToRank = new Dictionary<string, int>();
        Dictionary<int, string> playersRankToName = new Dictionary<int, string>();


        for (int i = 0; i < players.Length; i++)
        {
            playersNameToRank.Add(players[i], i);
            playersRankToName.Add(i, players[i]);
        }


        for (int i = 0; i < callings.Length; i++)
        {
           int currentRank = playersNameToRank[callings[i]];
           
           string currentName = playersRankToName[currentRank];
           string previousName = playersRankToName[currentRank - 1];
           
           playersNameToRank[previousName] = currentRank;
           playersNameToRank[currentName] = currentRank-1;
           
           playersRankToName[currentRank] =previousName;
           playersRankToName[currentRank-1] =currentName;
           
         
           
        }
        
        string[] answer = new string[players.Length];
        for (int i = 0; i < players.Length; i++)
        {
            answer[i] = playersRankToName[i];
        }
        
        return answer;
    }
}

딕셔너리를 하나만 사용하는 방법을 계속해서 생각해보다가 너무 오래 걸렸다.

결국 Dictionary 자료형은 Key값을 바탕으로 Value 값을 찾는 자료형이고 , 이는 굉장히 효율적이지만 

반대로 Value값을 토대로 Key값을 찾으려면 순회하여 찾는다. 그래서 메모리를 조금 더 쓰더라도 

Dict을 2개 사용하여 풀었다. 

 

이렇게 하면 좋은점은 편하다는 것이다. 결국 dictionary 2 개는 서로 영향을 미치지 않기에 그냥 쭈욱 써 주면 된다.

 

다른 사람의 흥미로운 풀이

 

  foreach(string c in callings)
        {
            int index = dict[c];
            dict[c]--;
            dict[players[index-1]]++;
            string temp = players[index];
            players[index] = players[index-1];
            players[index-1] = temp;
        }

 

이런 식으로 배열을 계속해서 수정하며 하는 방법도 있다. 

처음에 이렇게 생각했었는데 배열의 수정은 계속해서 새 배열을 만든다고 알고 있어서 비효율적이라고 생각했다.

 

반면 메모리 측면에서는 배열을 수정하는 것이 낫다고 한다. 

 

코딩테스트 : 공원 산책 

지나다니는 길을 'O', 장애물을 'X'로 나타낸 직사각형 격자 모양의 공원에서 로봇 강아지가 산책을 하려합니다. 산책은 로봇 강아지에 미리 입력된 명령에 따라 진행하며, 명령은 다음과 같은 형식으로 주어집니다.

["방향 거리", "방향 거리" … ]
예를 들어 "E 5"는 로봇 강아지가 현재 위치에서 동쪽으로 5칸 이동했다는 의미입니다. 로봇 강아지는 명령을 수행하기 전에 다음 두 가지를 먼저 확인합니다.

주어진 방향으로 이동할 때 공원을 벗어나는지 확인합니다.
주어진 방향으로 이동 중 장애물을 만나는지 확인합니다.
위 두 가지중 어느 하나라도 해당된다면, 로봇 강아지는 해당 명령을 무시하고 다음 명령을 수행합니다.
공원의 가로 길이가 W, 세로 길이가 H라고 할 때, 공원의 좌측 상단의 좌표는 (0, 0), 우측 하단의 좌표는 (H - 1, W - 1) 입니다.

공원을 나타내는 문자열 배열 park, 로봇 강아지가 수행할 명령이 담긴 문자열 배열 routes가 매개변수로 주어질 때, 로봇 강아지가 모든 명령을 수행 후 놓인 위치를 [세로 방향 좌표, 가로 방향 좌표] 순으로 배열에 담아 return 하도록 solution 함수를 완성해주세요.

using System;
using System.Collections.Generic;
using System.Linq;

public class Solution
{
    public int[] solution(string[] park, string[] routes)
    {
        int[] answer = new int[] { };
        int[] current = new int[2];


        int row = park.Length;
        int col = park[0].Length;

        bool[,] board = new bool[row, col];


        for (int i = 0; i < row; i++)
        {
            string currentrow = park[i];

            for (int j = 0; j < col; j++)
            {
                if (currentrow[j].ToString() == "O") board[i, j] = true;
                else if (currentrow[j].ToString() == "X") board[i, j] = false;
                else
                {
                    board[i, j] = true;
                    current[0] = i;
                    current[1] = j;
                }
            }
        }


        for (int i = 0; i < routes.Length; i++)
        {
            int[] origin = new int[2];
            for (int j = 0; j < 2; j++)
            {
                origin[j] = current[j];
            }

            string currentroute = routes[i];
            string direction = currentroute.Substring(0, 1);
            int distance = int.Parse(currentroute.Substring(2, 1));
            
            int directionInt = 0;
            if (direction == "N" || direction == "W") directionInt = -1;
            else if (direction == "S" || direction == "E") directionInt = 1;

            for (int j = 0; j < distance; j++)
            {
                if (direction == "N" || direction == "S") current[0] += directionInt;
                else if (direction == "W" || direction == "E") current[1] += directionInt;

                //갈 수 있는지 없는지 고려
                if (current[0] < 0 || current[1] < 0 || current[0] >= row || current[1] >= col
                    || !board[current[0], current[1]])
                {
                    current[0] = origin[0];
                    current[1] = origin[1];
                    break;
                }
            }
        }
        return new int[] { current[0], current[1] };
    }
}

 

블로그 글을 날려먹어서 노가다 했던 코드를 잃어버렸다. 이 전에는 각각 방향마다 if문을 사용해서 했었다.

그러니까 코드가 줄줄 늘어났고, 마침 튜플을 사용했는데 프로그래머스는 튜플을 지원하지 않기에 고치는 김에

이쁘게 고쳐봤다. (물론 이것도 길지만).

 

 

코딩테스트 : 유연근무제

문제 설명
프로그래머스 사이트를 운영하는 그렙에서는 재택근무와 함께 출근 희망 시각을 자유롭게 정하는 유연근무제를 시행하고 있습니다. 제도 정착을 위해 오늘부터 일주일 동안 각자 설정한 출근 희망 시각에 늦지 않고 출근한 직원들에게 상품을 주는 이벤트를 진행하려고 합니다.

직원들은 일주일동안 자신이 설정한 출근 희망 시각 + 10분까지 어플로 출근해야 합니다. 예를 들어 출근 희망 시각이 9시 58분인 직원은 10시 8분까지 출근해야 합니다. 단, 토요일, 일요일의 출근 시각은 이벤트에 영향을 끼치지 않습니다. 직원들은 매일 한 번씩만 어플로 출근하고, 모든 시각은 시에 100을 곱하고 분을 더한 정수로 표현됩니다. 예를 들어 10시 13분은 1013이 되고 9시 58분은 958이 됩니다.

당신은 직원들이 설정한 출근 희망 시각과 실제로 출근한 기록을 바탕으로 상품을 받을 직원이 몇 명인지 알고 싶습니다.

직원 n명이 설정한 출근 희망 시각을 담은 1차원 정수 배열 schedules, 직원들이 일주일 동안 출근한 시각을 담은 2차원 정수 배열 timelogs, 이벤트를 시작한 요일을 의미하는 정수 startday가 매개변수로 주어집니다. 이때 상품을 받을 직원의 수를 return 하도록 solution 함수를 완성해주세요.

using System;

public class Solution {
    public int solution(int[] schedules, int[,] timelogs, int startday)
    {
        int answer = schedules.Length ;

        for (int i = 0; i < timelogs.GetLength(0); i++)
        {
            for (int j = 0; j < timelogs.GetLength(1); j++)
            {
                if ((j + startday -1 ) % 7 < 5)
                {
                    if (schedules[i]+10 < timelogs[i, j])
                    {
                        answer--;
                        break;
                    }
                }
            }
        }
        return answer;
    }
}

 

왜 틀렸나 하고 한참 봤다.

 

시간 넘어가는 것을 잘못 계산했다.

예를 들어, 7시 50분에서 10을 더하면 760이 아니라 800이 나와야 한다. 

using System;

public class Solution {
    public int solution(int[] schedules, int[,] timelogs, int startday)
    {
        int answer = schedules.Length;

        for (int i = 0; i < timelogs.GetLength(0); i++)
        {
            for (int j = 0; j < timelogs.GetLength(1); j++)
            {
                if ((j + startday-1) % 7 < 5)
                {
                    int tempTime = schedules[i] + 10;
                    if (tempTime% 100 >= 60)
                    {
                        tempTime += 100;
                        tempTime -= 60;
                    }
                    if ( tempTime < timelogs[i, j])
                    {
                        answer--;
                        break;
                    }
                }
            }
        }
        return answer;
    }
}

 

숫자 바꾼거 복붙으로 덮어썼다가 모르고 한참 더 찾았다... 

다른 사람의 흥미로운 풀이

 

나름 깔끔하게 잘 푼 듯 하다.