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

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

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

 

 

1. 코드카타 문제풀이

A. 잃어버린 괄호(백준, 1541번)

문제 내용

 

문제 풀이 방법

  • 수식이 문자로 주어질 때, 수식의 값이 최소가 되는 경우를 출력.
  • string을 - 기호를 기준으로 split을 해 분할한 후, + 기호로 연결된 모든 수를 더해서 리스트에 저장 후 리스트의 값을 첫 번째 리스트 값만 더하고 나머지는 모두 빼서 결과를 도출할 수 있다.
    초기 수식: 55 - 50 + 40
    - 기호를 기준으로 분할: 55, 50 + 40
    + 기호의 값을 모두 더함: 55, 90
    결과의 첫 번째 데이터에 나머지 데이터를 모두 뺀 값: -35

 

해결 코드(스포 주의)

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

fun main() = with(BufferedReader(InputStreamReader(System.`in`))) {
    val formula = readLine()
    // 빼기 기호 뒤로 괄호를 묶어야 함.
    val subListMinus = formula.split("-")
    // - 로 split 후 +로 연결된 모든 수를 더한다.
    // 55 - 50 + 40
    // 55, 50 + 40
    // 55, 90
    val resultList = mutableListOf<Int>()
    for (i in subListMinus.indices) {
        val splitPlus = subListMinus[i].split("+")
        splitPlus.sumOf { it.toInt() }
        // + 를 기준으로 분할한 리스트의 길이가 1보다 크다(더할 항목들이 존재함.)
        if (splitPlus.size > 1) resultList.add(splitPlus.sumOf { it.toInt() })
        else resultList.add(subListMinus[i].toInt())
    }

    // 첫 번째 데이터를 제외한 모든 데이터를 빼준다.
    var result = resultList.first()
    for (i in 1 until resultList.size) {
        result -= resultList[i]
    }
    println(result)
}

 

풀이 과정

  • 입력받은 수식을 - 기호를 기준으로 분할해 준다(subListMinus).
  • +기호의 값을 계산할 resultList를 생성한다.
  • 반복문에서 + 기호를 기준으로 데이터를 분할(splitPlus)해준 후, splitPlus의 길이가 1보다 크면 더할 값이 있다는 뜻이기 때문에 sumOf을 이용해 합을 계산해 resultList에 추가한다.
    아닌 경우에는 데이터를 통으로 resultList에 추가한다.
  • resultList에 데이터가 모두 들어오면 첫 번째 데이터를 result 변수의 초기값으로 지정해 준다.
  • 1부터 resultList의 size 미만까지 반복해 result에 들어오는 값을 뺀다.

 

문제 해결 과정

  • 복잡하게 생각할 필요가 없는 문제였다.
  • 최솟값을 뽑아야 하기 때문에 큰 값을 빼야 최솟값이 될 수 있다.

 

B. A와 B(백준, 12904번)

문제 내용

 

문제 풀이 방법

  • 시작 문자열인 S가 주어질 때, S를 위의 2개의 연산을 이용해 T로 만들 수 있으면 1을, 아니면 0을 출력.
  • T에다가 연산들을 역순으로 돌려 문자열 S를 만들 수 있어도 가능하다.

 

해결 코드(스포 주의)

더보기
import java.io.BufferedReader
import java.io.InputStreamReader
import kotlin.system.exitProcess

fun main() = with(BufferedReader(InputStreamReader(System.`in`))) {
    val string = readLine()
    val complete = StringBuilder(readLine())

    // string, complete가 A와 B가 아닌 경우
    if (string.any { it != 'A' && it != 'B' }) {
        println(0)
        exitProcess(0)
    }
    if (complete.any { it != 'A' && it != 'B' }) {
        println(0)
        exitProcess(0)
    }

    // 초기 string의 맨 뒤 문자가 A냐 B냐에 따라서 동작이 달라야 함.
    // A면 뒤집고 B 추가
    // B면 A 추가
    // 2개의 로직을 상항에 따라 사용할 수 있어야 함.
    // 로직을 역순으로 돌면서 처음의 input과 같아지는지 체크하기
    while (string != complete.toString()) {
        // 문자열이 비어 있으면 반복 종료.
        if (complete.isEmpty()) break

        if (complete.last() == 'A') {
            // 맨 뒤의 문자가 a인 경우
            complete.deleteCharAt(complete.lastIndex)
        } else {
            // 맨 뒤의 문자가 b인 경우
            complete.reverse()
            complete.deleteCharAt(0)
        }
    }

    if (string == complete.toString()) println(1)
    else println(0)
}

 

풀이 과정

  • 입력받은 string과 complete가 A와 B가 아닌 경우에는 0을 출력하고 프로세스를 종료(exitProcess)한다.
    문제에 A와 B만 입력받는다고 적혀있지 않다.
  • complete가 string이랑 같아지거나 complete가 비어 있을 때까지 반복한다.
    역순으로 돌아야 하기 때문에 complete의 맨 뒤의 문자가 A인지 B인지 확인한다.
    A면 가장 마지막 문자인 A를 제거한다.
    B면 문자열을 뒤집은 후 가장 앞에 있는 문자를 제거한다.

 

문제 해결 과정

  • string을 complete로 만들려는 시도를 했었다.
    역순이 아닌 순차적으로 했을 때는, 채점 2%에서 실패했다. 질문하기에서 힌트를 얻어 역순으로 시도해 보았는데 역순으로 했는 데 성공했던 거 보면 처음에 내가 코드를 이상하게 짠 것 같았다. 내 코드를 봤다면 순차적으로 가도록 문제를 풀어도 될 듯하다.
  • 문제를 잘 읽어보자.
    문제 본문에는 A와 B만 입력된다는 문장이 없었다. 그래서 오답이 났었다 :(

 

2. 스파르타 코딩 클럽 강의 수강

A. Kotlin 문법 종합반 2주 차

1강(코딩 컨벤션)

  • 코딩 컨벤션이란? 다른 개발자도 이해하기 쉽도록 코드를 작성하는 규칙. 프로그래밍 언어마다 다르지만 어느 정도 겹친다.
  • 코딩 컨벤션이 필요한 이유는 코드의 가독성을 높일 수 있고 효율적인 협업이 가능하다.

 

  • 코딩 컨벤션에는 3가지의 방법이 있다.
  • 카멜 표기법(camelCase 표기법)
    • 낙타의 혹과 같이 첫 번째 단어를 제외한 단어들의 첫 글자에 대문자를 달아주는 표기법
    • 변수, 메서드에 이용
    • seoulFoodIsGood()
  • 스네이크 표기법(snake_case 표기법)
    • 뱀처럼 단어의 끝과 시작 사이에 밑줄(_)을 넣는 표기법
    • 상수에 이용
    • seoul_food_is_good()
  • 파스칼 표기법(PascalCase 표기법)
    • 모든 단어의 첫 글자에 대문자를 달아주는 표기법
    • 클래스에 이용
    • SeoulFoodIsGood()

 

2강(입력과 출력)

  • 출력이란? 프로그램에서 다른 장치로 데이터를 전송하는 행위
    • 모니터로 정보 출력
    • 스피커로 소리 출력
  • 입력이란? 다른 장치로부터 데이터를 불러와서 프로그램에서 확인하는 행위
    • 키보드에 입력한 내용을 불러와서 프로그램에서 확인
    • 마이크에서 녹음한 목소리를 불러와서 프로그램에서 확인
  • 코틀린의 입력과 출력
// 출력
println("caramm")

// 입력을 활용한 출력
val data = readLine()
println(data)

 

 

3강(자료형)

  • 자료형: 자료를 저장할 수 있는 적절한 형태.
  • 자료형의 종류는: Long, Int, Short, Byte, Double, Float, Char, Boolean, String이 있다.
  • 자료형이 중요한 이유
    • 컴퓨터의 하드웨어는 한정적이다.
    • Int로만 해도 충분한 작업을 Long으로 하는 것은 메모리 낭비이다.

 

4강(변수)

  • 변수와 상수
    • 변수는 var(variable) 키워드를 사용한다.
    • 상수는 val(value) 키워드를 사용한다.
// 변수 선언 방법
var num: Int = 1
var num1 = 1	// 자료형 정의 생략 가능(초기값이 있으면)

// kotlin은 변수의 타입이 정의되지 않아도 자신이 타입을 유추할 수 있다.
var one1 = '감'	// char로 유추한다.
var one2 = "참새"	// string으로 유추한다.

// 상수 선언 방법
val num2 = 1
// num2 = 11	// value는 재할당(값 변경)이 불가하다.

 

 

6강(연산자)

  • 연산자의 종류
    • 산술 연산자: 덧셈(+), 뺄셈(-), 곱셈(*), 나눗셈(/), 그리고 나머지(%) 연산을 가능하게 하는 연산.
    • 대입 연산자: 변수나 상수를 만들 때 사용하는 = 기호
    • 복합 대입 연산자: 산술연산자와 대입연산자를 한 번에 사용하는 연산자.
    • 증감 연산자: 1을 더하거나 빼는 특수한 경우에 사용하는 연산자(++, --)
    • 비교 연산자: 두 개의 변수 또는 상수의 관계나 값을 비교할 때 사용하는 연산자.
      • >, >=, <, <=, ==, !=

 

7강(조건문)

  • 조건문: 조건에 따라 프로그램을 실행하기 위한 방법
    • if, else, when 키워드를 활용해 조건을 관리한다.
    • 비교 연산자를 이용해 조건을 많이 작성한다.

 

8강(반복문)

  • 반복문: 조건에 맞게 코드를 반복적으로 실행
    • for, while 키워드를 통해 반복적인 로직을 관리한다.
    • 비교 연산자와 함께 사용한다.
    • break: 가장 가까운 반복문을 강제로 종료하고 다음 코드로 넘어간다.
    • continue: continue 아래의 코드를 실행하지 않고 다음 반복으로 넘어간다.

 

B. Kotlin 종합반 3주 차

1강(함수)

  • 메서드: 소스 코드에 이름을 붙이는 것.
// 함수 구조
fun 함수 이름(변수: 자료형...): 반환자료형 {
	// 소스 코드
}

 

  • 메서드를 사용하는 곳.
    • 로직을 만들어놓고 상황에 맞게 쓸 수 있다.
    • 코드의 재사용성을 높인다.

 

2강(클래스)

  • 객체지향 프로그래밍(OOP)
    • 코틀린은 모든 것이 클래스형태이므로 객체화할 수 있다.
    • 프로그램에서 필요한 데이터를 추상화시켜 상태와 행위를 가진 객체를 만든다.
    • 객체들 간의 적절한 결합을 통해 유지보수를 쉽게 한다.
    • 5대 키워드: 클래스, 추상화, 캡슐화, 상속, 다형성
  • 클래스: 프로그램의 각 요소별 설계도
    • 데이터 클래스(data class): 정보만 가지는 클래스
    • 실드 클래스(sealed class): 클래스 상속과 관련되어 있고, 상속받을 수 있는 자식 클래스를 미리 정의할 수 있다.
    • 오브젝트 클래스(object class): java의 static 대신 사용하는 클래스.
    • 열거 클래스(enum class): 여러 곳에 사용하기 위한 상수를 정의하거나, 상수 외부의 데이터를 정의하기 위한 클래스.

 

3강(생성자)

  • 생성자: 클래스를 실체화할 때 최초로 실행할 로직.
  • 한 가지의 형태로 클래스를 실체화할 때는 주 생성자를 활용.
    여러 형태로 클래스를 실체화할 때는 보조 생성자를 활용.

 

4강(객체의 활용)

  • 객체: 모든 인스턴스를 포함하는 개념
    클래스 타입으로 선언된 것을 객체라고 한다.
  • 인스턴스: 클래스 형태로 설계된 객체를 실체화하면 인스턴스가 생긴다.
    메모리 공간을 차지한다.

 

6강(상속)

  • 상속: 클래스 간의 관계를 맺어주는 장치
    공통적인 요소가 많다면 부모, 자식 클래스를 구분해서 상속관계를 만들 수 있다.
    기본적으로 상속이 불가하도록 final 키워드가 자동으로 붙어 상속이 막혀있기 때문에, open 키워드를 통해 상속이 가능한 클래스를 만들 수 있다.
  • 상속을 구현하면
    다형성을 구현하거나,
    클래스의 내용을 변경해야 하는 경우 부모 클래스만 변경하는 것으로 공수를 줄인다.

 

7강(오버라이딩)

  • 오버라이딩: 부모 클래스의 정보를 재설계할 수 있다.
    상속받은 부모 클래스의 정보나 메서드를 재설계할 수 있다.
    주로 부모 클래스의 행위(메서드)를 재설계하는 데 사용한다.
  • 오버라이딩을 하는 이유
    객체 지향 프로그래밍 관점에서는 클래스들 간의 관계를 만들어서 일관성을 유지하려는 목표를 가진다.
    만약 필요할 때마다 별도로 이름을 만들게 된다면 일관성을 해치게 된다.
    프로그램에 문제가 생기지는 않지만 재사용성이 떨어져 유지 보수가 어렵다.

 

8강(오버로딩)

  • 오버로딩: 동일한 이름의 메서드를 여러 형태로 만들 수 있다.
    매개변수의 개수를 다르게 하거나 자료형을 다르게 하면 오버로딩 메서드를 만들 수 있다.
    반환자료형은 오버로딩에 영향을 주지 않는다.
  • 오버로딩을 하는 이유
    2개의 매개변수를 받아서 더하는 add() 메서드를 만드려고 할 경우
    자료형마다 addInt(), addDouble()와 같이 만드는 것은 나중에 관리하기 힘들어진다.
    이 상황에서는 매개변수 자료형이 다르기 때문에 오버로딩으로 해결한다.

 

9강(인터페이스)

  • 인터페이스: 근본적인 공통점을 상속받고, 추가적인 기능들을 인터페이스를 만들어서 추가한다.
    interface 키워드를 사용.
  • 인터페이스를 사용하는 이유
    예를 들어 닭, 참새, 비둘기 클래스를 만들었을 때, 오리 클래스가 추가되면 문제가 생긴다.
    보통 새들은 헤엄치는 행위를 하지 않기 때문에 부모 클래스에 추가하는 것은 올바르지 않다.
    오리를 제외하고도 물에서 서식하는 조류들을 위한 별도의 기능을 만들어야 할 때 interface를 사용한다. 

 

3. 개인 공부

A. A -> B(백준, 16953번)

문제 내용

 

문제 풀이 방법

  • a와 b를 입력받았을 때, 2가지의 연산을 통해 a를 b로 만들 수 있을 때 필요한 연산의 횟수에 1을 더해 출력, 만들 수 없으면 -1을 출력.

 

해결 코드(스포 주의)

더보기
import java.util.Scanner

// 백준 16953번 A -> B
fun main() = with(Scanner(System.`in`)) {
    val start = nextInt()
    var complete = nextInt()

    // 홀수일 때,
    // 1003
    var calculation = 1     // 연산 횟수(1을 더한 값을 출력해야 하기 때문에 초기값을 1로).
    while (complete != start) {
        // 값이 0으로 딱 나누어 떨어진 경우.
        if (complete == 0) {
            calculation = -1
            break
        }

        if (complete.toString().toInt() % 2 == 0) {
            complete /= 2
        } else if (complete.toString().last() == '1') {
            complete = (complete - 1) / 10
        } else {
            calculation = -1
            break
        }

        calculation++
    }

    println(calculation)
}

 

풀이 과정

  • 연산 횟수를 저장할 calculation 변수를 만든다 초기값은 최소 연산 횟수에 1을 더해서 출력하기 때문에 1로 설정한다.
  • complete가 start와 같지 않거나 complete가 0이 아닐 때까지 반복한다.
    만약 2로 나누어 떨어지는 경우에는 complete에 2를 나눈 값을 대입해 주고,
    맨 뒤의 숫자가 1인 경우는 complete에 1을 빼로 10을 나눠준다(1을 빼면서 남은 자릿수도 처리할 수 있다).
    위 2개의 경우도 아닌 경우는 계산이 불가능하다는 뜻이므로 calculation을 -1로 바꾸고 반복을 끝낸다.

 

문제 해결 과정

  • 이전에 풀었던 A와 B 문제와 비슷했던 문제이다. 그래서 큰 어려움 없이 문제를 풀 수 있었다.

 


 

오늘 공부 내용 정리 및 회고

  • 오늘까지 코틀린 기초, 심화 문법을 공부했다.
  • 내일부터는 4주 차 강의를 들으면서 계산기를 만들게 될 텐데 빠르게 만들고 알고리즘 문제를 풀러 가야겠다.
728x90

댓글