CODEKATA 65 ~ 70

Tak Jeon·2025년 1월 13일

알고리즘

목록 보기
73/101

65번 문자열 나누기

/*
문제 분석
1. 정보
    - 문자열 S가 입력됨
    - 첫글자를 X라 지정
    - 문자열을 왼쪽에서 오른쪽으로 읽으면서, X와 X가 아닌 다른 글자들이 나온 횟수를 각각 셈
    - 처음으로 두 횟수가 같아지는 순간 멈추고, 해당 위치까지의 문자열을 분리
    - S에서 분리한 문자열을 빼고 남은 부분에 대해서 해당 과정 반복
    - 만약 두 횟수가 다른 상태에서 더 이상 읽을 글자가 없다면 읽은 문자열 분리 후 종료
2. 목표
     - S가 주어질 때, 분리한 문자열의 개수 리턴
     
3. 제약 조건
    - 1 <= S의 길이 <= 10000
    - S는 영어 소문자로 이루어져 있음

풀이
1. 아이디어
    - S의길이가 10000 이므로 while문 사용해도 충분
    - 첫 글자를 char 형태로 받음
    - 해당 글자의 개수 ++
    - 이후 조건에 맞을때 까지 다음 글자를 비교하여 개수에 더함
    - 두 개수가 같다면 해당 인덱스 while문 빠져나오고, answer++
    - 여기서 두 while의 ()에 들어갈 조건은 idx = 0으로 설정이후, idx < s.length()일때까지.
*/


class Solution {
        public int solution(String s) {
            int answer = 0;
            int idx = 0;
            int[] sum;
            char first;

            while (idx < s.length()) {
                sum = new int[2];
                first = s.charAt(idx++);
                sum[0]++;
                while (idx < s.length()) {
                    if (s.charAt(idx++) == first) {
                        sum[0]++;
                    } else {
                        sum[1]++;
                    }
                    if (sum[0] == sum[1]) {
                        break;
                    }
                }
                answer++;
            }
            return answer;
        }
    }

66번 대충 만든 자판

/*
문제 분석
1. 정보
    - 휴대폰 자판은 하나의 키게 여러 개의 문자가 할당 될 수 있음
    - 예로, 1번 키에 "A","B","C" 순서대로 할당되어 있다면, 3번 누르면 C가 되는 방식
    - 같은 규칙을 적용해 만든 휴대폰 자판이 있음
        - 같은 문자가 자판 전체에 여러 번 할당 된 경우도 있고,
        - 키 하나에 같은 문자가 여러번 할당 된 경우도 있음
        - 아예 할당되지 않은 경우도 있음
2. 목표
    - 해당 자판을 이용해 특정 문자열을 작성할 때, 키를 최소 몇 번 눌러야 그 문자열을 작성할 수 있는지 출력
    - 만약 문자열을 만들 수 없다면, -1을 출력
3. 제약 조건
    - 1 <= 자판의 길이 <= 100
        - 1 <= 특정 자판의 문자열 길이 <= 100
    - 각 자판의 문자열의 길이는 다를 수 있음
    - 각 원소는 알파벳 대문자로 이루어져 있음
    - 1 <= 목표 문자열 개수 <= 100
        - 1 <= 목표 문자열의 길이 <= 100

풀이
1. 아이디어
    - 해당 알파벳을 뽑는데 필요한 최소 누름 횟수를 저장하기 위한 배열을 선언
        - click[] = new int[26]으로 하고, 최대 100번 눌러야 뽑을 수 있는 경우의 수가 있기 때문에, 101로 초기화
    - keymap의 문자열을 다 순회
        - 해당 keymap의 문자를 하나씩 꺼내 click[] 과 idx + 1을 비교, 더 작은 값으로 업데이트.
    - 모든 keymap이 끝나면, target을 모두 순회
        - target의 문자열에서 문자를 하나씩 뽑음
            - 문자에 해당하는 click의 값이 101일 경우, -1 값 저장
            - 101이 아니면 sum에 해당 값을 더함
            - 모든 문자를 뽑은 후 answer배열에 sum 값 저장
*/

class Solution {
        public int[] solution(String[] keymap, String[] targets) {
            int[] answer = new int[targets.length];
            int[] click = new int[26];
            Arrays.fill(click, 101);
            for (int i = 0; i < keymap.length; i++) {
                for (int j = 0; j < keymap[i].length(); j++) {
                    int idx = keymap[i].charAt(j) - 'A';
                    click[idx] = Math.min(click[idx], j + 1);
                }
            }

            for (int i = 0; i < targets.length; i++) {
                int sum = 0;
                for (int j = 0; j < targets[i].length(); j++) {
                    int idx = targets[i].charAt(j) - 'A';
                    if (click[idx] == 101) {
                        sum = -1;
                        break;
                    } else {
                        sum += click[idx];
                    }
                }
                answer[i] = sum;
            }

            return answer;
        }
    }

67번 둘만의 암호

/*
문제 분석
1. 정보
    - 두 문자열 S, skip, 자연수 index가 주어질 때, 아래 규칙에 따라 문자열은 만듬
        - 문자열 S의 각 알파벳을 index만큼 뒤의 알파벳으로 바꿔줌
        - index 만큼의 뒤의 알파벳이 z를 넘어갈 경우 다시 a로 돌아감
        - skip에 있는 알파벳은 제외하고 건너뜀
2. 목표
    - 위 내용이 주어질 때, 규칙대로 s를 변환한 결과를 return
3. 제약 조건
    - 5 <= s <= 50
    - 1 <= skip <= 10
    - s와 skip은 소문자로만 이루어짐
        - skip에 포함되는 알파벳은 s에 없음
    - 1 <= index <= 20

풀이
1. 아이디어
    - 최대 50 * 20 -> 1000 바로 index를 더해주지 않고 하나씩 풀어나가도 가능
    - 먼저 boolean[]배열 선언해 해당 알파벳이 스킵되는지 유무 설정
        - 스킵 된다면 index - 1 하지 않고 넘어감
    - index = 0 이 될때가 변환된 암호

*/

class Solution {
        public static String solution(String s, String skip, int index) {
            StringBuilder sb = new StringBuilder();
            boolean[] check = new boolean[26];
            for (int i = 0; i < skip.length(); i++) {
                check[skip.charAt(i) - 'a'] = true;
            }

            for (int i = 0; i < s.length(); i++) {
                int cnt = index;
                int cur = s.charAt(i) - 'a';
                while (cnt > 0) {
                    if (!check[(cur + 1) % 26]) {
                        cnt--;

                    }
                    cur = (cur + 1) % 26;
                }
                sb.append((char) (cur + 'a'));
            }
            return sb.toString();
        }
    }

68번 햄버거 만들기

/*
문제 분석
1. 정보
    - 조리 된 재료를 조리된 순서대로 상수가 아래서 위로 햄버거를 쌓음
    - 정해진 순서는 빵-야채-고기-빵으로 쌓인 햄버거만 포장 가능
    - 재료의 높이는 무시
    - 예로, 재료의 순서가 [야채 빵 빵 야채 고기 빵 야채 고기 빵] 일때
        - 상수는 6번째 재료가 쌓였을 때, 3번째 재료부터 여섯 번째 재료를 이용하여 햄버거를 포장
        - 9번째 재료가 쌓였을 때, 2번째 재료와 7 ~ 9 번째 재료를 이용하여 햄버거를 포장
    - 1 : 빵
    - 2 : 야채
    - 3 : 고기
    - 를 의미
    - 즉 1 2 3 1 순으로 들어올때, 햄버거 포장 가능

2. 목표
    - 포장 가능한 햄버거의 개수를 출력

3. 제약 조건
    - 1 <= 재료의 길이 <= 1,000,000
    - 재료는 1, 2, 3 중 하나의 값

풀이
1. 아이디어
     - Stack 사용
     - 재료를 하나씩 Stack에 추가
     - Stack의 마지막 4개 요소가 1 2 3 1 순서라면
        - 마지막 4개 요소 제거
        - 햄버거 포장++
     - Stack에서 모든 햄버거를 포장 가능할 때 까지 반복
*/

class Solution {
        public int solution(int[] ingredient) {
            Stack<Integer> stack = new Stack<>();
            int[] seq = {1, 3, 2, 1};
            int answer = 0;
            for (int cur : ingredient) {
                stack.push(cur);

                if (stack.size() >= 4) {
                    boolean flag = true;
                    for (int i = 0; i < 4; i++) {
                        if (stack.get(stack.size() - (i + 1)) != seq[i]) {
                            flag = false;
                        }
                    }
                    if (flag) {
                        answer++;
                        for (int i = 0; i < 4; i++) {
                            stack.pop();
                        }
                    }
                }
            }

            return answer;
        }
    }

69번 성격 유형 검사

/*
문제 분석
1. 정보
     - 성격 유형 검사는 다음과 같은 4개 지표로 셩격 유형을 구분함
        - 1번 지표 : 라이언형(R), 튜브형(T)
        - 2번 지표 : 콘형(C), 프로도형(F)
        - 3번 지표 : 제이지형(J), 무지형(M)
        - 4번 지표 : 어피치형(A), 네오형(N)
    - 4개의 지표가 있으므로, 성격 유형은 총 16가지가 나올 수 있음
    - 검사지에는 총 N개의 질문이 있고, 아래와 같은 7개의 선택지가 존재
        - 매우 비동의
        - 비동의
        - 약간 비동의
        - 모르겠음
        - 약간 동의
        - 동의
        - 매우 동의
    - 각 질문은 1가지 지표로 성격 유형 점수를 판단
    - 예를 들어,
        - 매우 비동의 : 네오형 3점
        - 비동의 : 네오형 2점
        - 약간 비동의 : 네오형 1점
        - 모르겠음 : 0점
        - 약간 동의 : 어피치형 1점
        - 동의 : 어피치형 2점
        - 매우 동의 : 어피치형 3점
    - 질문에 따라 비동의와 동의의 형이 주어짐
    - 검사 결과는 모든 질문의 성격 유형 점수를 더하여 각 지표에서 더 높은 점수를 받은 성격 유형이 검사자의 성격 우형
        - 만약 하나의 지표에서 각 성격 유형 점수가 같다면, 사전순으로 빠른 성격 유형을 선택
2. 목표
    - 검사자의 성격 유형 검사 결과를 지표 번호 순서대로 return
3. 제약 조건
    - 1 <= 검사 질문 지표 <= 1000
    - "AB"형태로 들어옴
        - 왼쪽 char가 비동의 관련, 오른쪽 char가 동의 관련
    - 검사의 길이 = 검사 질문 지표의 길이


풀이
1. 아이디어
    - 단순 구현
        - 먼저 int[] 배열을 만들음. 대문자 알파벳의 개수를 길이로 하는 배열을 만들어 점수를 담음
        - survey의 길이 만큼 for문 수행
            - i번째의 choice 값을 가져옴.
            - case문을 만들어 수행
                - 1 : 왼쪽 char값에 해당하는 배열에 3 추가
                - 2 : 왼쪽 char값에 해당하는 배열에 2 추가
                - 3 : 왼쪽 char값에 해당하는 배열에 1 추가
                - 4 : 점수 추가 없음
                - 5 : 오른쪽 char값에 해당하는 배열에 1 추가
                - 6 : 오른쪽 char값에 해당하는 배열에 2 추가
                - 7 : 오른쪽 char값에 해당하는 배열에 3 추가
        - 모든 survey 가 수행되었으면,
            - R과 T 비교
            - C와 F 비교
            - J와 M 비교
            - A와 N 비교
                - 하여 더 큰값, 값이 같다면 사전순으로 빠른 값을 answer에 추가
        - answer return
*/

class Solution {
        public String solution(String[] survey, int[] choices) {
            int[] score = new int[26];

            for (int i = 0; i < survey.length; i++) {
                int left = survey[i].charAt(0) - 'A';
                int right = survey[i].charAt(1) - 'A';
                switch (choices[i]) {
                    case (1) -> score[left] += 3;
                    case (2) -> score[left] += 2;
                    case (3) -> score[left] += 1;
                    case (5) -> score[right] += 1;
                    case (6) -> score[right] += 2;
                    case (7) -> score[right] += 3;
                }
            }

            StringBuilder sb = new StringBuilder();
            if (score['R' - 'A'] >= score['T' - 'A']) {
                sb.append("R");
            } else {
                sb.append("T");
            }

            if (score['C' - 'A'] >= score['F' - 'A']) {
                sb.append("C");
            } else {
                sb.append("F");
            }

            if (score['J' - 'A'] >= score['M' - 'A']) {
                sb.append("J");
            } else {
                sb.append("M");
            }

            if (score['A' - 'A'] >= score['N' - 'A']) {
                sb.append("A");
            } else {
                sb.append("N");
            }

            return sb.toString();
        }
    }

70번 바탕화면 정리

/*
문제 분석
1. 정보
    - 머쓱이는 작성한 코드를 컴퓨터 바탕화면에 아무 위치에 저장
    - 작성한 코드가 많아짐에 따라, 프로그래머스에서 작성했던 코드는 바탕화면에서 삭제하기로 함
    - 바탕화면은 각 칸이 정사각형인 격자
    - 바탕화면의 상태를 나타낸 문자열 배열 wallpaper가 주어짐
        - (0,0)이 시작
        - 빈칸은 .
        - 파일이 있는 칸은 #
        - 드래그를 하면 파일을 선택할 수 있고, 선택한 파일을 삭제할 수 있음
        - 드래그는 다음과 같음
            - 격자점 S(lux,luy)에서 E(rdx,rdy)까지 드래그 했을 경우,
                - 점 S에서 점 E로 드래그한다 라고 표현
                - 드래그 한 거리 : |rdx - lux| + |rdy - luy|
2. 목표
    - 드래그 한 거리가 최소가 되는 값의 lux, luy, rdx, rdy를 출력
3. 제약 조건
    - 1 <= 격자판의 높이 <= 50
    - 1 <= 격자판의 너비 <= 50
    - 바탕화면에는 적어도 하나의 파일이 있음

풀이
1. 아이디어
    - lux, luy, rdx, rdy를 선언
    - wallpaper 배열을 왼쪽 위부터 오른쪽 아래까지 순차적으로 방문
    - 해당 격자에 #이 있다면, 위 4개에 적절히 업데이트
    - 모든 격자판을 방문한 이후, 위 4개의 정보를 활용해 드래그 범위를 구함
*/

class Solution {
        public int[] solution(String[] wallpaper) {
            int lux = 51;
            int luy = 51;
            int rdx = 0;
            int rdy = 0;
            for (int i = 0; i < wallpaper.length; i++) {
                for (int j = 0; j < wallpaper[i].length(); j++) {
                    if (wallpaper[i].charAt(j) == '#') {
                        lux = Math.min(lux, i);
                        luy = Math.min(luy, j);
                        rdx = Math.max(rdx, i + 1);
                        rdy = Math.max(rdy, j + 1);
                    }
                }
            }

            return new int[]{lux, luy, rdx, rdy};
        }
    }
profile
문제 해결을 좋아하는 개발자 입니다 :)

0개의 댓글