티스토리 뷰

코드카타

 

카펫

 

문제

 

카펫은 갈색 타일이 노란색 타일을 둘러싼 형태여야 한다.

 

갈색 타일 수와 노란색 타일 수가 매개변수로 주어질 때

해당 카펫의 가로, 세로 크기를 리스트 담아 반환하는 문제이다.

 

 

제한 사항

 

카펫의 가로 길이는 세로길이보다 같거나 길다고 언급되어있다.

 

 

입출력 예시

 

카펫의 크기가 n * m 일 때,  brown은 2(n + m) - 4의 값을 가진다.

이는 올바른 카펫 형태를 검사하는 조건에 해당한다.

 

 

풀이 과정

해당 문제를 해결하려면 (가로, 세로)형태의 경우의 수를 찾아야한다.

가로와 세로를 곱한 값은 총 타일 개수에 해당한다.

 

만약에 brown = 10, yellow = 2 라고 했을 때 12의 약수를 구해 짝을 지으면

(1, 12) , (2, 6) , (3, 4) , (4, 3) , (6, 2) , (12, 1) 와 같은 경우의 수가 나온다.

 

가로의 길이가 세로보다 길거나 같기에 (1, 12) , (2, 6) , (3, 4)의 경우의 수는 제외힌다.

 

또한, 가운데에 노란색 격자가 위치하기 위해선 가로, 세로 길이가

모두 3 이상이여야하기에 (6, 2) , (12, 1)의 경우의 수는 제외하여

최종적으로 (4, 3)이 카펫의 가로 세로 길이가 된다.

 

 

풀이

class Solution {
    fun solution(brown: Int, yellow: Int): List<Int> {
        var res = mutableListOf<Int>() // 결과 리스트 초기화
        val tiles = brown + yellow // 전체 타일 개수
        
        // (카펫 최소 높이 ~ 타일 개수) 범위 순회
        for (h in 3..tiles) { 
            // 전체 타일 수가 높이로 나누어 떨어지면
            if (tiles % h == 0) {
                // 너비 계산 후
                val w = tiles / h  
                // 갈색 타일 수가 조건에 맞다면
                if (2 * (w + h) - 4 == brown) {
                    // 가로 세로 크기를 리스트에 추가 후 반복문 종료
                    res.add(w)
                    res.add(h)
                    break
                }
            }
        }
        
        return res
    }
}

카펫의 크기는 (너비 x 높이)에 해당하므로 카펫의 높이가 타일개수와 나누어 떨어진다면

카펫의 너비는 타일개수에서 카펫의 높이를 나눈 값이 된다.

 


 

Kotlin 문법 강의 4주차 정리

 

접근 제한자

 

접근 제한자란?

객체 지향 프로그래밍에서 클래스의 변수 및 메서드에 대한

접근 권한을 제어하는 데 사용되는 키워드들이다.

 

 

위치 용어 정리

 

프로젝트: 최상단 개념으로, <모듈, 패키지, 클래스>를 포함한다.

 

 

 

모듈: 프로젝트 아래의 개념으로 <패키지, 클래스>를 포함한다.

 

 

 

패키지: 모듈 아래의 개념으로, <클래스>를 포함한다.

 

 

Kotlin 접근 제한자의 종류

public: 어디서나 접근할 수 있다. (접근 제한자를 명시하지 않으면 public으로 선언됨)
private: 동일한 클래스 내부에서만 접근할 수 있다.
internal: 같은 모듈 내부에서만 접근할 수 있다.
protected: 기본적으로 private이지만 상속을 받은경우에 타 모듈에서 접근할 수 있다.

 

 

접근제한자 쓰는 이유

접근 제한자를 쓰는 이유는 데이터의 무분별한 접근을 막기 위해서이다.

클래스들 간의 접근제어를 정의하면 추후에 유지보수가 용이해진다. 

 

 

예제 코드

open class AccessModifier {
    val a = 1
    private val b = 2
    internal val c = 3
    protected val d = 4
}

class UseProtected : AccessModifier(){
    val protectedVal = d
}

fun main() {
    val accessModifier = AccessModifier()
    val useProtected = UseProtected()

    println(accessModifier.a)
    println(accessModifier.c)

    println(useProtected.protectedVal)
}

b는 private로 선언되어 있기에 main에서 출력할 수 없다.

 

protected로 선언된 d를 출력하려면 해당 프로퍼티가 위치한 클래스를

상속하는 클래스를 만들어 그 클래스의 public으로 선언된 멤버를 호출해야한다.

 

 

간단 정리

간단한 프로젝트 할 땐 public과 private개념정도만 알고 있으면 된다.

 

public은 클래스에서 갖다 쓸 멤버를 선언할 떄 쓰고,

private는 클래스 내에서만 쓸 멤버를 선언할 떄 쓴다.

 

 

 

예외처리의 활용

 

"예외"의 정의

에러에는 프로그램을 실행하기 전 알 수 있는 컴파일 에러와,

프로그램 실행 도중에 발생하는 런타임 에러, 즉 예외가 존재한다.

 

 

예외 처리란?

실행 도중 예외가 발생하는 것을 막기 위해 진행하는 것이 예외 처리이다.

코틀린에서는 try-catch와 throw로 예외처리를 진행한다.

 

 

try-catch

fun method1() {
    try {
        예외가 발생할 가능성이 존재하는 코드
    } catch(예외종류) {
        예외가 발생했을때 처리할 코드
    }
}

try에는 예외 발생 가능성이 있는 코드를

catch에는 예외 처리를 진행할 코드를 작성한다.

 

 

throw

fun method2(num1:Int) {
    if(num1 > 10) {
        throw 예외종류
    }
}

throw는 예외를 던질 때 사용하는 키워드이다.

예외가 발생했을 때의 처리는 따로 하지 않는다.

 

 

예외 처리가 필요한 이유

프로그램이 도중에 종료되는 것을 방지하기 위해서이다.

예외처리를 진행하면 프로그램의 안정성을 높일 수 있다.

 

 

예외 확인

fun main() {
    print(1/0)
}

나눗셈 연산을 할 때 제수가 0이라면 예외가 발생한다.

 

 

 

콘솔창에서 해당 예외가 무슨 예외에 해당하는지 확인해준다.

 

 

예외처리 개념

fun divide(a: Int, b: Int): Int {
    if (b == 0) {
        throw ArithmeticException("0으로 나눌 수 없습니다.")
    }
    return a / b
}

fun main() {
    val a = 10
    val b = 0

    try {
        val result = divide(a, b)
        println("나눗셈 결과: $result")
    } catch (e: ArithmeticException) {
        println("나눗셈 오류 발생: ${e.message}")
    } finally {
        println("나눗셈 연산 완료")
    }
}

divdie 함수에서 ArithmeticException라는 예외가 발생했을 때

그 예외의 메시지를 throw로 정의해준다.

 

try 블럭은 예외가 발생하지 않았을 때 실행이 된다.

catch 블럭은 지정한 예외가 발생하였을 때 실행이 된다.

finally 블럭은 예외 발생 여부와 상관없이 실행이 된다.

 

b(제수)는 0이므로 main()에서는 catch와 finally 블럭만을 실행시킨다.

 

 

예외처리 예시

// 숫자를 입력해야하는데 실수로 문자를 입력했을때의 예외를 처리

while(true) {
    try {
        var num1 = readLine()!!.toInt()
        println("내가 입력한 숫자는 ${num1}입니다")
        break
    } catch(e:java.lang.NumberFormatException) {
        println("숫자를 입력하세요")
    }
}

try 블럭이 실행될 때 숫자를 입력할 때까지,

즉 예외가 발생하지 않을 때까지 계속해서 입력을 받는다. 

 

 

 

지연초기화

 

지연초기화란?

코틀린에서는 클래스를 설계할 때 안정성을 위해 반드시 변수의 값을 초기화하도록 한다.

이 떄 초기값을 정의하기 난처하다면 나중에 대입하기 위해 지연초기화 키워드를 사용한다.

 

저사양으로 제한되어있는 환경에서 메모리를 더욱 효율적으로 사용하기 위해 쓰는 키워드이다.

 

 

지연초기화 문법

fun main() {
    val student = Student()
    student.name = "주영"
    println("${student.name}의 성별은 ${student.gender}이다.")
}

class Student {
    lateinit var name: String
    val gender by lazy { "남성" }
}

변수를 초기화할 때는 lateinit을, 상수를 초기화할 때는 lazy 키워드를 사용한다.

 

변수를 지원초기화하려면 클래스 내에서 변수의 타입을 지정해줘야하고 

변수를 사용하기 전에 해당 변수를 타입에 맞는 값으로 초기화 해줘야 한다.

 

지원초기화 된 상수는 해당 상수가 호출되는 시점에서 지정한 값으로 초기화 된다.

 

 

초기화 확인

fun main() {
    val student = Student()
    student.studentInfo()
}

class Student {
    lateinit var name: String
    val gender by lazy { "남성" }

    fun studentInfo() {
        if(this::name.isInitialized) {
            println("${name}의 성별은 ${gender}이다.")
        } else {
            println("name 변수를 초기화해주세요.")
        }
    }
}

isInitialized를 활용해서 변수가 초기화 되었는지 확인할 수 있다.

해당 문법을 사용할 땐 값이 아니라 참조형태로 사용해야하므로 this:: 를 앞에 붙인다.

 

 

 

널 세이프티

 

널 세이프티란?

Null 예외를 방지하기 위해 쓰는 문법이다.

코틀린은 안전한 설계를 위해 자료형에 Null 여부를 명시할 수 있다.

 

 

널 세이프티 키워드

!! => Null 아님을 보장한다.
?. => Null이 아닐때만 참조하는 메소드를 실행한다.
?: => 값이 Null이면 설정해둔 다른 값으로 초기화한다.

 

 

 

배열

 

배열이란?

동일한 자료형의 요소들이 메모리 상에서 연속적으로 나열된 자료구조이다.

반복적으로 변수에 접근할 필요가 있는 로직을 구현할 때 사용한다.

 

 

배열 개념

// arrayOf메소드를 호출하면 배열을 리턴한다
var arr = arrayOf(1,2,3,4,5)

// 배열요소를 모두 출력한다
println(Arrays.toString(arr))

// 배열의 첫번째 요소에 저장된 값을 출력한다
// 배열의 인덱스는 0부터 시작하고 선언한 배열 크기는 5이므로 0 ~ 4 번지에 접근 가능하다
// 배열의 n번지값, 즉 배열의 요소는 하나의 변수로 취급이 된다
println(arr[0])

 

 

 

컬렉션

 

컬렉션이란?

개발에 유용한 자료구조를 지원하는 것으로,

코틀린에서는 리스트, 맵, 집합 자료구조를 지원한다.

 

배열과 달리 크기가 정해져있지 않아 동적으로 값을 추가할 수 있다.

 

 

List

// 불변형 리스트
val scores1 = listOf(1, 2, 3)
// 가변형 리스트
val scores2 = mutableListOf(1, 2, 3)

불변형 리스트는 한 번 생성된 이후에는 요소를 추가, 삭제, 변경할 수 없지만,

가변형 리스트는 생성된 후에도 요소를 추가, 삭제, 변경할 수 있다.

 

 

Map

fun main() {
    // 불변형 맵으로 변수명[키]로 데이터에 접근할 수 있다
    var scoreInfo1 = mapOf("kor" to 94, "math" to 90, "eng" to 92)
    println(scoreInfo1["kor"])

    // 가변형 맵으로 데이터 접근 뿐 아니라 키값의 변경 또한 가능하다
    var scoreInfo2 = mutableMapOf("kor" to 94, "math" to 90)
    scoreInfo2["eng"] = 92
    println(scoreInfo2["eng"])

    // 맵의 키와 값을 동시에 추출해서 사용할 수 있다
    for((k,v) in scoreInfo2) {
        println("${k}의 값은 ${v}입니다")
    }
}

코틀린에서 Map 자료형은 키(key)와 값(value)의 쌍으로 데이터를 저장하고 관리할 때 사용한다.

이 자료형은 특정 키를 통해 해당 키에 연결된 값을 빠르게 찾아낼 수 있다.

 

 

Set

fun main() {
    // 귀여운 새의 집합
    val birdSet = setOf("닭", "참새", "비둘기", "물오리")

    // 날 수 있는 새의 집합
    val flyBirdSet = setOf("참새", "비둘기", "까치")

    // 모든 새의 집합 (합집합)
    val unionBirdSet = birdSet.union(flyBirdSet)

    // 귀엽고 날 수 있는 새의 집합 (교집합)
    val intersectBirdSet = birdSet.intersect(flyBirdSet)

    // 귀여운 새들 중에서 날 수 없는 새의 조합 (차집합)
    val subtractBirdSet = birdSet.subtract(flyBirdSet)
}

Set은 순서가 존재하지 않고 중복되는 요소가 없는 집합 자료형이다

다른 컬렉션들은 요소를 찾는데에 집중하지만, Set은 요소가 존재하는지에 집중한다

 

Set을 이용해 집합 간의 교집합, 차집합, 합집합을 구할 수 있다.

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/09   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30
글 보관함