본문 바로가기
♞ | 공부일지

[Android, 내일배움캠프] 공부일지(2024-06-10)

by immgga 2024. 6. 10.
오늘 공부한 내용 정리(2024년 6월 10일)

 

 

1. 코드카타 문제풀이

A. 균형 잡힌 세상(백준, S4, 4949번)

문제 내용

 

문제 풀이 방법

  • 균형 잡힌 문자열이면 yes, 아니면 no 출력.
  • 균형 잡힌 문자열이 되기 위해서는
    소괄호는 소괄호끼리, 대괄호는 대괄호끼리 짝을 이룬다.
    모든 오른쪽 괄호는 짝을 이루는 왼쪽 괄호가 있어야 한다.
    괄호는 1:1 매칭만 가능하다.
  • Help( I[m being held prisoner in a fortune cookie factory)]. 다음과 같은 문자열이 주어지면 이 문자열은 균형 잡힌 문자열이 아니다.
    괄호 순서가 (, [, ), ]이기 때문에 매칭될 수 없다.

 

해결 코드(스포 주의)

더보기
import java.io.BufferedReader
import java.io.InputStreamReader
import java.util.Stack

fun main() = with(BufferedReader(InputStreamReader(System.`in`))) {
    val brackets = Stack<Char>()

    while (true) {
        var isCorrect = ""
        val input = readLine()
        if (input == ".") break

        // stack에 괄호 문자열을 넣기
        // 봐야 할 stack의 괄호가 닫는 괄호일 때, 바로 다음에 여는 괄호가 나와야 한다.
        for (i in input.indices) {
            if (input[i] == '[' || input[i] == '(') brackets.push(input[i])
            else if (input[i] == ']') {
                // 닫는 소괄호가 존재할 경우 스택이 비어있거나 다음 데이터가 여는 괄호여야 올바른 문자이다.
                if (brackets.isEmpty() || brackets.peek() != '[') isCorrect = "no"
                else brackets.pop()
            } else if (input[i] == ')') {
                if (brackets.isEmpty() || brackets.peek() != '(') isCorrect = "no"
                else brackets.pop()
            }
        }

        // for의 조건에서 걸러진 isCorrect를 stack이 비어있다고 해서 yes로 바꾸면 안되므로 isCorrect가 비어있지 않을 때만 yes로 변경;
        isCorrect = if (brackets.isEmpty() && isCorrect.isEmpty()) "yes" else "no"
        println(isCorrect)

        // 재시작 전 stack 초기화
        brackets.clear()
    }
}

 

풀이 과정

  • 괄호만 담을 stack을 생성한다.
  • 문자열이 올바른지 판단할 isCorrect를 생성한다. 초기화는 빈 문자열로 한다.
  • 입력을 마침표(.)만 입력받을 때까지 반복한다.
    입력받은 문자열에서 여는 괄호 [, ( 가 있으면 stack에 push 한다.
    입력받는 문자에 닫는 괄호 ], )가 있으면 스택이 비어 있거나, stack의 다음 데이터가 동일한 종류의 여는 괄호가 아니면 isCorrect를 no로 설정한다.
  • 반복을 돌고 나서 스택이 비어있고 isCorrect에 빈 값(위의 for문에서 균형 잡힌 문자열이 아닌 경우의 if문에 전부 해당하지 않는 경우)이면 yes로 설정하고 아니면 no로 설정하고 출력.

 

문제 해결 과정

  • 기존에는 stack을 사용하지 않고 mutablelist를 이용해서 해결하고자 했다.
  • 코드를 구현하고 테스트 단계에서 위에서 언급한 Help( I[m being held prisoner in a fortune cookie factory)]. 에서 막혔다.
    짝을 이루는 두 괄호가 있을 때, 그 사이의 문자열도 균형이 잡혀야 한다는 조건에 첫 번째 대괄호가 I[m과 같은 형식으로 되어 있어 문자열이 균형 잡혀 있지 않겠다는 생각을 했었다.
    하지만 전혀 상관이 없었고 오직 괄호의 순서와 종류, 개수만 고려하면 되는 문제였다.
  • stack을 이용하면 더 빠르게 구현이 가능하다 해서 stack을 사용했다.

 

B. 선로에 마네킹이야!!(백준, B1, 15920번)

문제 내용

 

문제 풀이 방법

  • 2가지의 동작을 수행할 수 있다.
    W(1초 기다리기): a -> b, b -> c, c면 변하지 않음.
    P(레버 당기기): 당김 <-> 당기지 않음 번갈아가면서 반복.
  • 초기의 선로는 5개의 마네킹이 묶여 있는 선로로 시작한다.
  • 광차는 a -> b로 이동할 때, 레버를 당기면 1개의 마네킹이 있는 선로로 가고 그렇지 않으면 그대로 진행.
    b구역에서 레버를 1번이라도 당기면 두 선로를 동시에 지나게 되기 때문에 깔리는 마네킹이 6개가 된다.
    c구역에 도착하면 마네킹이 개수에 맞는 선로만큼 깔리게 된다.
  • 총 깔린 마네킹의 수를 출력.

 

해결 코드(스포 주의)

더보기
import java.util.Scanner

fun main() = with(Scanner(System.`in`)) {
    // 1초 기다리기: a -> b, b -> c, c면 변하지 않음.
    // 레버 당기기: 당김 -> 당기지 않음, 당기지 않음 -> 당김.
    // 광차
    // 초기 선로는: 5개의 마네킹이 묶여 있는 선로
    // a -> b로 이동할 때, 레버가 당기지 않은 상태면 5개 마네킹 쪽으로 그대로 감. 레버를 당겼으면 1개 마네킹 쪽으로 감.
    // b구역에서 레버를 당기면 두 선로를 동시에 타게 되어 6개가 깔리게 됨.
    // c구역에 도착하면 선로의 모든 마네킹이 깔린다.
    // 입력
    // P: 레버를 당김
    // W: 1초 기다리기, 구역 이동.
    nextInt()
    val movement = next().map { it }
    var currentArea = "a"
    var lever = false       // false: 당기지 않음(5). true: 당김(1).
    var dieSoon = 5     // 곧 깔릴 마네킹의 개수
    var result = 0      // 최종적으로 깔린 마네킹.
    for (move in movement) {
        when (move) {
            'W' -> {
                when (currentArea) {
                    "a" -> currentArea = "b"
                    "b" -> currentArea = "c"
                    "c" -> currentArea = "c"
                }
            }
            'P' -> {
                if (currentArea == "b") {
                    // b구역에서 레버를 움직이면 멀티트랙 드리프팅이 발생해 2개의 선로를 동시에 타게 됨.
                    lever = !lever
                    dieSoon = 6
                } else {
                    lever = !lever
                    dieSoon = if (lever) 1 else 5
                }
            }
        }

        // c구역이면 마네킹을 죽이고 종료.
        if (currentArea == "c") {
            result += dieSoon
            break
        } else result = 0
    }

    println(result)
}

 

풀이 과정

  • 현재 구역(a, b, c) 이름(currentArea), 레버 상태를 나타내는 변수(lever), 곧 깔리는 마네킹의 개수(dieSoon), result 변수를 생성.
  •  이동이 W이면 구역을 옮긴다는 뜻이므로 현재 area에 따른 다른 area로 이동.
  • 이동이 P이면 레버를 당긴다는 뜻이다. 현재 구역(currentArea)이 b이고 레버를 한 번 이상 당겼으면 dieSoon을 6으로 변경.
    그 외의 경우는 lever의 상태에 따라 dieSoon을 1 또는 5로 변경.
  • 그리고 반복을 돌면서 항상 현재 구역이 c인지 확인해야 한다. c에 도달하고 남은 동작들은 모두 무용지물이기 때문에 c에 도착했으면 result에 dieSoon을 더해주고 반복 종료.

 

문제 해결 과정

  • c 구역에 도달하면 뒤의 동작들이 필요가 없다는 점과
    b구역에서 레버를 1번 이상 돌린 경우(2번 돌려 다시 원래 상태로 돌려놔도 안됨) 깔릴 마네킹을 6으로 만드는 것만 주의해서 구현하면 큰 문제는 없었던 문제이다.

 

2. 내일배움캠프 강연

A. 계산기 과제 해설

강의 내용 간단 정리

  • lv.1부터 lv.5까지의 정확한 구현 방법을 알려 주셨다.
  • 나는 하나의 파일에 모든 override 함수를 구현했지만 해설강의의 코드는 개별적으로 구현했다는 점.
  • 해설 강의는 반복문을 적절히 활용해 적은 반복문으로 오타 입력 방지를 위한 코드를 구현했다.
  • 해설 강의에 비해 내쪽 코드는 콘솔 UI를 예쁘게(?) 만들었다는 점, 내 코드는 직접 모든 수식을 입력받아 계산하는 대신 괄호 계산은 할 수 없고, 해설 강의의 코드는 stack에 직접 불러오는 함수를 만들어 그 함수의 파라미터에 직접 수식을 입력해 넣어주어야 했다. 하지만 괄호까지 계산한다.

 


 

오늘 공부 내용 정리 및 회고

  • 오늘은 solved.ac에 생긴 마라톤 문제를 많이 풀어본 날이다.
    beakjoon online judge 사이트에서 지원하는 문제 난이도 별 티어를 매겨주는 프로그램이다.
    유명한 만큼 문제풀이에 도움이 될만한 블로그들이 많다.
  • solved.ac의 마라톤 문제 덕에 7문제를 풀었지만 분량과 난이도 상 가장 어렵다고 느낀 2문제만 올렸다.
  • 오늘 들은 기초 문법 특강 강의는 ppt가 정리돼서 노션에 올라오는 날(내일 예상)에 함께 복습 겸 정리해서 til로 올리겠다.
728x90

댓글