CODEKATA 71 ~ 75

Tak Jeon·2025년 1월 14일

알고리즘

목록 보기
74/101

71번 개인정보 수집 유효기간

/*
문제 분석
1. 정보
    - 1 ~ N번으로 분류된 개인정보 N개가 존재
    - 약관 종류는 여러가지가 있으며 각 약관마다 개인정보 보관 유효기간이 정해져 있음
    - 수집된 개인정보는 유효기간 전까지만 보관 가능하며, 유효기간이 지났다면 반드시 파기해야함.
    - 모든달은 28일까지 있다고 가정

2. 목표
    - 파기해야할 개인정보를 return

3. 제약 조건
    - 1 <= 약관의 유효기간 개수 <= 20
    - A <= 약관 종류 <= Z
    - 1 <= 유효기간 <= 100
    - 1 <= 수집된 개인정보 <= 100
    - 2000 <= 연 <= 2022
    - 1 <= 월 <= 12
    - 1 <= 일 <= 28

풀이
1. 아이디어
    - 먼저 각 약관의 유효기간을 int[] 배열에 저장함
    - privacies를 돌면서 하나씩 비교
        - 먼저 공백을 기준으로 분리
            - 앞에는 날짜, 뒤에는 약관 종류
            - 날짜를 다시 .을 기준으로 분리
            - 약관의 유효기간을 월에 더함
                - 이때 (유효기간 + 현재 월) / 12를 구해 연에 더해주고
                - (유효기간 + 현재 월) % 12 부분에 1을 추가하여 더해줌
            - 날짜를 다시 합치고 today와 비교
                - today보다 작거나 같다면 파기해야할 대상
                - result에 해당 idx 추가
*/

import java.util.*;

class Solution {
        public int[] solution(String today, String[] terms, String[] privacies) {
            List<Integer> result = new ArrayList<>();
            today = today.replaceAll("\\.", "");
            int[] valid = new int[26];
            for (int i = 0; i < terms.length; i++) {
                String[] tmp = terms[i].split(" ");
                valid[tmp[0].charAt(0) - 'A'] = Integer.parseInt(tmp[1]);
            }

            for (int i = 0; i < privacies.length; i++) {
                String[] splitYnT = privacies[i].split(" ");
                String[] date = splitYnT[0].split("\\.");

                date[1] = String.valueOf((Integer.parseInt(date[1]) + valid[splitYnT[1].charAt(0) - 'A']));

                if (Integer.parseInt(date[1]) > 12) {
                    date[0] = String.valueOf(Integer.parseInt(date[0]) + Integer.parseInt(date[1]) / 12);
                    date[1] = String.valueOf(Integer.parseInt(date[1]) % 12);
                }

                if (Integer.parseInt(date[1]) == 0) {
                    date[0] = String.valueOf(Integer.parseInt(date[0]) - 1);
                    date[1] = "12";
                }

                String fin = date[0] + String.format("%02d", Integer.parseInt(date[1]))+ date[2];
                
                if (Integer.parseInt(today) >= Integer.parseInt(fin)) {
                    result.add(i + 1);
                }
            }

            int[] answer = new int[result.size()];
            for (int i = 0; i < answer.length; i++) {
                answer[i] = result.get(i);
            }
            Arrays.sort(answer);

            return answer;
        }
    }

72번 달리기 경주

/*
문제 분석
1. 정보
    - 얀에서는 달리기 경주가 열림
    - 해설진들은 선수들이 자기 바로 앞의 선수를 추월할 때, 추월한 선수의 이름을 부름
        - 예를 들어,
            - 1 : 무무, 2 : 소, 3 : 포 일때
            - 해설진이 소를 불렀다면, 소가 무무를 추월했다는 뜻

2. 목표
    - 해설진들이 부르는 소리를 이용해 최종 등수를 배열에 담아 return

3. 제약 조건
    - 5 <= 선수 <= 50000
    - 2 <= 해설 길이 <= 1,000,000

풀이
1. 아이디어
    - 선수의 콜링이 들을때마다 일일히 선수의 위치를 찾아 바꾼다면 시간초과 가능성 존재
    - 따라서 선수의 이름과 현재 등수를 Map 배열에 같이 저장해두어 찾을때 편하게 찾을 수 있도록 함
    - 콜링에 해당하는 선수의 현재 등수를 가져오고, 해당 등수 - 1인 선수와 자리를 바꿈
    - 마찬가지로 map의 데이터도 수정해줌
    - 모든 콜링이 끝나고, player 그대로 return
*/

import java.util.*;

class Solution {
        public String[] solution(String[] players, String[] callings) {
            Map<String, Integer> map = new HashMap<>();
            for (int i = 0; i < players.length; i++) {
                map.put(players[i], i);
            }

            for (String call : callings) {
                int callRank = map.get(call);

                players[callRank] = players[callRank - 1];
                players[callRank - 1] = call;

                map.put(players[callRank - 1], callRank - 1);
                map.put(players[callRank], callRank);
            }
            return players;
        }
    }

73번 공원 산책

/*
문제 분석
1. 정보
     - 직사각형 격자모양의 공원이 존재
        - O : 지나갈 수 있는 길
        - X : 장애물
     - 명령은 다음과 같이 주어짐
        - ["방향 거리", "방향 거리", ...]
     - 만약 해당 명령을 수행할때
        - 공원을 벗어나거나
        - 장애물에 마주하는 경우
     - 해당 명령을 무시하고 다음 명령을 수행
     
2. 목표
    - 시작지점 S에서 시작해서 모든 명령을 수행하고 난 후의 좌표를 출력
3. 제약 조건
    - 3 <= 공원 높이 <= 50
    - 3 <= 공원 너피 <= 50
    - 1 <= 명령 개수 <= 50
        - 명령은 OP N으로 구성
        - OP : N S W E중 하나
        - 1 <= N <= 9

풀이
1. 아이디어
    - 구현 문제
        - 받은 park 배열에서 S를 찾아 시작지점으로 지정
        - 명령을 순서대로 수행
            - 해당 명령을 수행할 수 없는 조건이 발생하면
            - 다음 명령 수행
            - 수행할 수 있다면, 현재 위치 업데이트
        - 모든 명령을 수행한 후 결과 좌표 return
*/

class Solution {
        public int[] solution(String[] park, String[] routes) {
            int[] answer = findStart(park);
            int H = park.length;
            int W = park[0].length();
            for (int i = 0; i < routes.length; i++) {
                char dir = routes[i].charAt(0);
                int len = routes[i].charAt(2) - '0';

                if (isAvailable(park, answer, dir, len, H, W)) {
                    switch(dir){
                        case 'N' -> answer[0] -= len;
                        case 'S' -> answer[0] += len;
                        case 'W' -> answer[1] -= len;
                        case 'E' -> answer[1] += len;
                    }
                }
            }

            return answer;
        }

        public boolean isAvailable(String[] park, int[] cur, char dir, int len, int H, int W) {
            int[] tmp = cur.clone();
            for (int i = 0; i < len; i++) {
                switch(dir){
                    case 'N' -> tmp[0]--;
                    case 'S' -> tmp[0]++;
                    case 'W' -> tmp[1]--;
                    case 'E' -> tmp[1]++;
                }

                if (tmp[0] < 0 || tmp[0] >= H || tmp[1] < 0 || tmp[1] >= W) {
                    return false;
                }

                if(park[tmp[0]].charAt(tmp[1]) == 'X'){
                    return false;
                }
            }
            return true;
        }

        public int[] findStart(String[] park){
            int[] start = new int[2];
            for (int i = 0; i < park.length; i++) {
                for (int j = 0; j < park[i].length(); j++) {
                    if (park[i].charAt(j) == 'S') {
                        start[0] = i;
                        start[1] = j;
                        return start;
                    }
                }
            }
            return start;
        }
    }

74번 신고 결과 받기

/*
문제 분석
1. 정보
    - 무지가 개발하려는 시스템은 다음과 같음
        - 각 유저는 한 번에 한 명의 유저를 신고 가능
            - 신고 횟수에 제한은 없음. 서로 다른 유저를 계속 신고 가능
            - 한 유저를 여러번 신고할 수도 있지만, 동일한 유저에 대한 신고는 1회로 처리
        - k번 이상 신고된 유저는 게시판 이용이 정지되며, 해당 유저를 신고한 모든 유저에게 정지 사실을 메일로 발송
            - 유저가 신고한 모든 내용을 취합하여 마지막에 한꺼번에 게시판 이용 정지를 시키면서 정지 메일을 발송

2. 목표
    - 각 유저가 받는 메일의 개수를 배열로 return

3. 제약 조건
    - 2 <= 유저의 수 <= 1000
    - 1 <= 신고 횟수 <= 200000
    - 1 <= k <= 200

풀이
1. 아이디어
    - 먼저 id_list를 활용하여 Map<String, Integer> userId를 만들어 Id를 저장
    - 또한, boolean[][] check 배열을 만들어 i 유저가 j 유저에게 신고당했는지 저장
    - report를 모두 탐색
        - 해당 report에서 왼쪽은 신고한사람, 오른쪽은 신고를 당한 사람
        - 따라서 userId에서 왼쪽과 오른쪽의 id값을 찾아 check[j][i] = true;
    - 모든 report가 끝났다면,
        - check 배열을 순회
            - 만약 i번째 사람이 신고당한 횟수가 k 이상이면 다시 돌면서 신고 한사람들의 answer에 1씩 추가
    - 이후 answer return
*/

import java.util.*;

class Solution {
        public int[] solution(String[] id_list, String[] report, int k) {
            Map<String, Integer> users = new HashMap<>();
            for (int i = 0; i < id_list.length; i++) {
                users.put(id_list[i], i);
            }
            int[] answer = new int[id_list.length];
            boolean[][] check = new boolean[id_list.length][id_list.length];

            for (int i = 0; i < report.length; i++) {
                String[] su = report[i].split(" ");
                int left = users.get(su[0]);
                int right = users.get(su[1]);
                check[right][left] = true;
            }

            for (int i = 0; i < check.length; i++) {
                int sum = 0;
                for (int j = 0; j < check[i].length; j++) {
                    if (check[i][j]) {
                        sum++;
                    }
                }
                if (sum >= k) {
                    for (int j = 0; j < check[i].length; j++) {
                        if (check[i][j]) {
                            answer[j]++;
                        }
                    }
                }
            }

            return answer;
        }
    }

75번 최댓값과 최솟값

/*
문제 분석
1. 정보
    - 문자열 S에는 공백으로 구분된 숫자들이 저장되어 있음
    
2. 목표
    - S에 나타나는 숫자중 최솟값과 최댓값을 찾아 반환
3. 제약 조건
    - S에는 둘 이상의 정수가 공백으로 구분


풀이
1. 아이디어
    - S문자열을 split을 사용해 공백을 기준으로 나눔
    - 최솟값과 최댓값을 저장하기 위한 integer 선언
    - 나눠진 문자열들을 순회
        - 해당 문자열을 Integer로 바꾼 뒤
            - 최솟값보다 작다면 최솟값 업데이트
            - 최댓값보다 크다면 최댓값 업데이트
    - min + " " + max로 return
*/

class Solution {
        public String solution(String s) {
            String[] split = s.split(" ");
            int min = Integer.MAX_VALUE;
            int max = Integer.MIN_VALUE;
            for (String cur : split) {
                int curNum = Integer.parseInt(cur);
                min = Math.min(min, curNum);
                max = Math.max(max, curNum);
            }
            String answer = min + " " + max;
            return answer;
        }
    }
profile
문제 해결을 좋아하는 개발자 입니다 :)

0개의 댓글