연습문제풀이-2

Practice1

문제 설명

로마 숫자 표기를 정수형으로 변환하는 프로그램을 작성하세요.

로마 숫자 표기법은 I, V, X, L, C, D, M 으로 이루어져있다.

로마 숫자 정수형
I 1
V 5
X 10
L 50
C 100
D 500
M 1000

로마 숫자 표기 방식

  • 큰 기호에서 작은 기호 방향으로 작성 (XI, VI, II, …)
  • 다음의 경우 작은 기호가 큰 기호 앞에 올 수 있다.
    • I 는 V 와 X 의 앞에 올 수 있다. (IV: 4, IX: 9)
    • X 는 L 과 C 의 앞에 올 수 있다. (XL: 40, XC: 90)
    • C 는 D 와 M 의 앞에 올 수 있다. (CD: 400, CM: 900)
입력 출력
“III” 3
“IV” 4
“VI” 6
“XIII” 13
“XXVI” 26
“MCMXCIV” 1994
import java.util.HashMap;

public class Practice1 {
    public static void solution(String s) {
        // 해시 맵으로 로마 숫자 표기 우선 초기화
        HashMap<Character, Integer> map = new HashMap<>();
        map.put('I', 1);
        map.put('V', 5);
        map.put('X', 10);
        map.put('L', 50);
        map.put('C', 100);
        map.put('D', 500);
        map.put('M', 1000);
        
        int sum = 0;
        char[] arr = s.toCharArray();
        for (int i = 0; i < arr.length - 1; i++) {
            // 작은 표기가 앞에 온 경우 뺌
            if (map.get(arr[i]) < map.get(arr[i + 1])) {
                sum -= map.get(arr[i]);
            } else { // 일반 표기 순서의 경우 더함
                sum += map.get(arr[i]);
            }
        }
        sum += map.get(arr[arr.length - 1]);
        System.out.println(sum);
    }

    public static void main(String[] args) {
        // Test code
        solution("III");
        solution("IV");
        solution("VI");
        solution("XIII");
        solution("XXVI");
        solution("MCMXCIV");
    }
}
3
4
6
13
26
1994

Practice2

문제 설명

정수형 숫자를 로마 숫자 표기로 변환하는 프로그램을 작성하세요.

로마 숫자 표기법은 I, V, X, L, C, D, M 으로 이루어져있다.

로마 숫자 정수형
I 1
V 5
X 10
L 50
C 100
D 500
M 1000

로마 숫자 표기 방식

  • 큰 기호에서 작은 기호 방향으로 작성 (XI, VI, II, …)
  • 다음의 경우 작은 기호가 큰 기호 앞에 올 수 있다.
    • I 는 V 와 X 의 앞에 올 수 있다. (IV: 4, IX: 9)
    • X 는 L 과 C 의 앞에 올 수 있다. (XL: 40, XC: 90)
    • C 는 D 와 M 의 앞에 올 수 있다. (CD: 400, CM: 900)

입출력 예시

입력 출력
3 “III”
4 “IV”
6 “VI”
13 “XIII”
26 “XXVI”
1994 “MCMXCIV”

public class Practice2 {

    public static String solution(int num){
        String result = "";
        // 로마 숫자 표기 방법 규칙 적용 역순 나열
        String[] roman = {"M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"};
        int[] values = {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1 };

        int i = 0;
        // 입력 num 이 0보다 큰 동안
        while (num > 0) {
            // 로마 숫자 표기 법 중 큰 수부터 현재 num 에서 뺄 수 있는지 체크
            while (num >= values[i]) {
                num -= values[i];
                result += roman[i];
            }
            i++;
        }

        return result;
    }

    public static void main(String[] args) {
        // Test code
        System.out.println(solution(3));
        System.out.println(solution(4));
        System.out.println(solution(6));
        System.out.println(solution(13));
        System.out.println(solution(26));
        System.out.println(solution(1994));
    }
}
III
IV
VI
XIII
XXVI
MCMXCIV

Practice3

문제 설명

간단한 편집기를 구현하려고 한다.

편집기에는 문자열과 편집 명령어가 주어지는데, 명령어의 동작은 다음과 같다.

  • L : 커서를 왼쪽으로 한 칸 옮김 (커서가 문장의 맨 앞이면 무시)
  • D : 커서를 오른쪽으로 한 칸 옮김 (커서가 문장의 맨 뒤이면 무시)
  • B : 커서 왼쪽에 있는 문자를 삭제 (커서가 문장의 맨 앞이면 무시)
  • P x : x라는 문자를 커서 왼쪽에 추가

여기서 커서는 문자열에서 편집이 시작되는 기준 위치로,
문장의 맨 앞, 맨 뒤, 중간에 위치할 수 있다.

편집기에 문자열과 명령어들이 주어졌을 때,
편집을 완료한 후의 문자열을 출력하는 프로그램을 작성하시오.
(초기 커서의 위치는 문장의 맨 뒤에서 시작한다.)
(문자열은 소문자만 입력 가능하다.)

초기 문자열 명령어 결과 출력
“aba” “L B” “aa”
“abcd” “P x L P y” “abcdyx”
“abc” “L L L P x L B P y” “yxabc”
“a” “B B L L D D P a P b P c” “abc”
import java.util.ArrayList;

public class Practice3 {
    public static String solution(String input, String cmd) {
        // 문자열의 편집이 빈번할 때 유리한 StringBuffer 로 변환하여 사용
        StringBuffer sb = new StringBuffer(input);
        ArrayList<String> cmdArr = new ArrayList<>();

        // 명령어들 분할하여 배열에 추가
        for (String s: cmd.split(" ")) {
            cmdArr.add(s);
        }

        // 초기 커서 위치
        int curSor = sb.length();
        // 명령어 배열의 인덱스로 사용할 변수
        int cmdIdx = 0;
        while (cmdIdx != cmdArr.size()) {
            String cur = cmdArr.get(cmdIdx);

            if (cur.equals("L")) {
                // 0일 때는 -1로 가지 않도록
                curSor = Math.max(0, curSor - 1);
            } else if (cur.equals("D")) {
                // 가장 맨 끝일 때는 그 이상 넘어가지 않도록
                curSor = Math.min(sb.length(), curSor + 1);
            } else if (cur.equals("B")) {
                // 커서가 맨 앞일 때는 지울게 없으므로  continue
                if (curSor == 0) {
                    cmdIdx++;
                    continue;
                }
                // 해당 위치의 문자 삭제 후 커서 재조정
                sb.delete(curSor - 1, curSor);
                curSor = Math.max(0, curSor - 1);
            } else if (cur.equals("P")) {
                String s = cmdArr.get(++cmdIdx);
                sb.insert(curSor, s);
                curSor += 1;
            }

            cmdIdx++;
        }

        return sb.toString();
    }

    public static void main(String[] args) {
        // test code
        System.out.println(solution("aba", "L B"));
        System.out.println(solution("abcd", "P x L P y"));
        System.out.println(solution("abc", "L L L P x L B P y"));
        System.out.println(solution("a", "B B L L D D P a P b P c"));
    }
}
aa
abcdyx
yxabc
abc

Practice4

문제 설명

특수 작전을 위해 상대방의 PC에 키보드 입력 내용을 얻을 수 있는 키로깅 프로그램을 설치했다.

해당 키로깅 프로그램으로부터는 아래와 같이 특정 값으로 내용이 수신된다.

  • 8 : Backspace
  • 16 : Shift
  • 20 : Caps Lock
  • 32 : Space bar
  • 37 : 키보드 왼쪽 화살표
  • 39 : 키보드 오른쪽 화살표
  • 155: Insert
  • 127: Delete
  • 97~122: 알파벳 소문자 (기본 입력은 소문자 기준, Shift 나 Caps Lock 에 의해 변경)
  • 48~57: 숫자 0~9

(이 외의 값은 들어오지 않는다고 가정)

키로깅 프로그램으로부터 수신된 데이터를 원래 내용으로 복구하는 프로그램을 작성하세요.

수신 내용 결과
16, 106, 101, 108, 108, 111, 37, 37, 37, 37, 37, 155, 16, 104 “Hello”
20, 104, 16, 105, 32, 20, 16, 106, 97, 118, 97 “Hi Java”
49 51 8 50 51 53 55 37 37 127 127 52 53 “12345”
20 65 66 16 67 16 68 49 50 51 “ABcd!@#”

public class Practice4 {
    public static String solution(int[] keyLog) {
        final int BACK_SPACE = 8;
        final int SHIFT = 16;
        final int CAPS_LOCK = 20;
        final int SPACE_BAR = 32;
        final int KEY_LEFT = 37;
        final int KEY_RIGHT = 39;
        final int INSERT = 155;
        final int DELETE = 127;

        StringBuffer sb = new StringBuffer();

        int step = (int)('a' - 'A');

        int curSor = 0;
        int cmdIdx = 0;
        boolean isShift = false;
        boolean isCapsLock = false;
        boolean isInsert = false;
        while (cmdIdx != keyLog.length) {
            int cur = keyLog[cmdIdx];
            
            // backspace 는 이전과 동일
            if (cur == BACK_SPACE) {
                if (curSor == 0) {
                    cmdIdx++;
                    continue;
                }
                sb.delete(curSor - 1, curSor);
                curSor = Math.max(0, curSor - 1);
            } else if (cur == SHIFT) {  // shift 입력은 해당 변수 true 로 변경
                isShift = true;
            } else if (cur == CAPS_LOCK) {  // CapsLock 은 한 번 누르면 지속 (토글)
                isCapsLock = !isCapsLock;
            } else if (cur == SPACE_BAR) {
                inputData(sb, ' ', curSor, isInsert);   // 공백 문자 입력 후 커서 증가
                curSor += 1;
            } else if (cur == KEY_LEFT) {
                curSor = Math.max(0, curSor - 1);
            } else if (cur == KEY_RIGHT) {
                curSor = Math.min(sb.length(), curSor + 1);
            } else if (cur == INSERT) { // Insert 는 한 번 누르면 지속 (토글)
                isInsert = !isInsert;
            } else if (cur == DELETE) { // Delete 는 backspace 와 커서 부분 살짝 다름
                if (curSor == sb.length()) {
                    cmdIdx++;
                    continue;
                }
                sb.delete(curSor, curSor + 1);
            } else if (cur >= 97 && cur <= 122) { // 알파벳 입력 부분
                int data = cur;
                // CapLock 켜진 상태에서 Shift 누르면 다시 소문자
                if (isCapsLock && isShift) {
                    data = cur;
                } else if (isCapsLock || isShift) { // 둘 중 하나가 true 면 대문자로 변경
                    data -= step;
                }
                inputData(sb, (char)data, curSor, isInsert);
                isShift = false;
                curSor += 1;
            } else if (cur >= 48 && cur <= 57) {
                if (isShift) {
                    // 각 숫자에 대응하는 특수문자 배열 (인덱스 0 부터 시작 -> ')')
                    char[] specialKey = {')', '!', '@', '#', '$', '%', '^', '&', '*', '('};
                    inputData(sb, specialKey[cur - '0'], curSor, isInsert);
                } else {
                    inputData(sb, (char)cur, curSor, isInsert);
                }
                isShift = false;
                curSor += 1;
            }

            cmdIdx++;
        }

        return sb.toString();
    }

    public static void inputData(StringBuffer sb, char data, int curSor, boolean isInsert) {
        // Insert 가 false 면 해당 위치에 삽입 true 면 해당 위치 변경
        if (isInsert == false) {
            sb.insert(curSor, data);
        } else {
            sb.setCharAt(curSor, data);
        }
    }


    public static void main(String[] args) {
        // Test code
        int[] keyLog = {16, 106, 101, 108, 108, 111, 37, 37, 37, 37, 37, 155, 16, 104};
        System.out.println(solution(keyLog));

        keyLog = new int[]{20, 104, 16, 105, 32, 20, 16, 106, 97, 118, 97};
        System.out.println(solution(keyLog));

        keyLog = new int[]{49, 51, 8, 50, 51, 53, 55, 37, 37, 127, 127, 52, 53};
        System.out.println(solution(keyLog));

        keyLog = new int[]{20, 97, 98, 16, 99, 16, 100, 16, 49, 16, 50, 16, 51};
        System.out.println(solution(keyLog));
    }
}
Hello
Hi Java
12345
ABcd!@#

Practice5

문제 설명

N 명의 아이들이 한 줄로 서있다.
각각의 아이들은 점수 표를 가지고 있는데 점수 표에 따라 다음과 같은 규칙으로 사탕을 나누어 줘야 한다.

  • 적어도 1개 이상의 사탕을 나누어줘야 한다.
  • 점수가 높은 아이에게는 바로 옆의 아이 보다는 사탕을 많이 줘야 한다.

N 명의 아이들에 대한 점수 표가 ratings 배열에 주어질 때,
나누어 줘야하는 최소한의 사탕 개수를 출력하세요.

입력 출력
1 2 3 6
3 2 1 6
1 0 2 5
1 2 2 4
1, 3, 5, 3, 1, 3, 5, 7, 5, 3, 1, 0 29

public class Practice5 {
    public static int solution(int[] ratings) {
        if (ratings == null || ratings.length == 0) {
            return 0;
        }

        int result = 1;
        int upCnt = 1;
        int downCnt = 0;
        int peak = 0;
        for (int i = 1; i < ratings.length; i++) {
            // 다음 순번의 rating 이 더 높은 경우, upCnt 증가, peak 갱신, downCnt 쪽은 0으로 초기화
            if (ratings[i] > ratings[i - 1]) {
                upCnt++;
                peak = upCnt;
                downCnt = 0;
                result += upCnt;
            } else if (ratings[i] == ratings[i - 1]) {
                // 다음 순번과 rating 이 같은 경우는 1 개 주면 됨
                // upCnt 는 1로, downCnt 와 peak 는 0으로 초기화
                upCnt = 1;
                downCnt = 0;
                peak = 0;
                result += 1;
            } else {
                // 다음 순번의 rating 이 낮은 경우, downCnt 증가, upCnt 쪽은 1로 초기화
                downCnt++;
                upCnt = 1;
                result += downCnt;
                // rating 이 낮은 쪽으로 진행되다가 앞의 peak 를 넘어선 경우 1 씩 더해줌
                if (peak <= downCnt) {
                    result += 1;
                }
            }
        }

        return result;
    }

    public static void main(String[] args) {
        // Test code
        int[] ratings = {1, 2, 3};
        System.out.println(solution(ratings));

        ratings = new int[]{3, 2, 1};
        System.out.println(solution(ratings));

        ratings = new int[]{1, 0, 2};
        System.out.println(solution(ratings));

        ratings = new int[]{1, 2, 2};
        System.out.println(solution(ratings));

        ratings = new int[]{1, 3, 5, 3, 1, 3, 5, 7, 5, 3, 1, 0};
        System.out.println(solution(ratings));
    }
}
6
6
5
4
29

Tags:

Categories:

Updated:

Leave a comment