N개의 최소공배수

주어진 배열의 모든 수의 최소공배수를 구해야한다.

배열의 요소 두 수를 가져와 최소공배수와 최대공약수를 구하고 구해진 최소공배수를 다음 수와 계산해 최대공약수와 최소공배수를 마지막 요소까지 구해준다.
예전에 최소 공배수 문제가 나왔을때 공부했던 유클리드 호제법을 이용해 풀 수 있었다.


나의풀이

class Solution {
    fun solution(arr: IntArray): Int {
        var answer = arr[0]
        var tempGcd = 0
        for ( i in 1 until arr.size){
            tempGcd = gcd(answer, arr[i])
            answer = lcm(answer, arr[i], tempGcd)
        }
        return answer
    }
    
    tailrec fun gcd(a: Int, b: Int): Int {
        return if (b == 0) a else gcd(b, a % b)
    }
    
    fun lcm (a:Int, b: Int, gcd: Int) = a * b / gcd
}

다른사람의 풀이

class Solution {
    fun solution(arr: IntArray): Int {
        var answer = 1
        while(true) {
            var x = 0
            for(a in arr) x += answer%a
            if(x==0) return answer
            answer++
        }
        return answer
    }
}

코틀린 문법강의

유용한 기능

자료형 변환

  • 숫자 자료형끼리 to자료형() 메소드를 활용할 수 있음
  • 문자열을 숫자로 변경할때 별도의 메소드 필요

객체 자료형간의 변환

  • 객체 자료형간의 변환은 상속관계에서 가능

업캐스팅: 자식클래스 -> 부모클래스

var birds = mutableListOf<Bird>()
birds.add(Sparrow(name) as Bird)

Sparrow는 Bird의 자식클래스라 Bird로 형변환해 리스트에 넣을 수 있다.
as Bird부분은 생략이 가능하다.

다운캐스팅: 부모클래스 -> 자식클래스

var s1:Sparrow = birds.get(0) 

Sparrow는 Bird가 가져야할 정보를 모두 가지고 있지 않으면 오류가 난다.

자료형 타입확인

  • 코틀린은 is로 자료형의 타입을 확인할 수 있다.
	if(name is String) {
    	println("name은 String 타입입니다")
	} else {
    	println("name은 String 타입이 아닙니다")
	}

복수의 데이터 다루기

  • 메소드는 기본적으로 하나의 데이터를 리턴
  • 두개의 데이터는 데이터클래스를 설계하면 가능하지만 매번 불필요한 클래스를 만드는 것은 비효율적임

복수의 데이터 리턴방법

  • Pair를 사용해 두 개의 인스턴스 리턴
	var chicken = Chicken()
    var eggs = chicken.getEggs()
    var listEggs = eggs.toList()
    
    // first, second로 관리
    var firstEgg = eggs.first
    var secondEgg = eggs.second
    
    // 리스트로 관리
    var firstEgg = listEggs[0]
    var secondEgg = listEggs[1]
}

class Chicken {
    fun getEggs(): Pair<String, String> {
        var eggs = Pair("달걀", "맥반석")
        return eggs
    }
}
  • Triple을 사용해 세 개의 인스턴스 리턴
fun main() {
    var chicken = Chicken()
    var eggs = chicken.getThreeEggs()
    var listEggs = eggs.toList()
    
    // first, second, third로 관리
    var firstEgg = eggs.first
    var secondEgg = eggs.second
    var eggTime = eggs.third
    
    // 리스트로 관리
    var firstEgg = listEggs[0]
    var secondEgg = listEggs[1]
    var eggTime = listEggs[2]
}

class Chicken {
    fun getThreeEggs(): Triple<String, String, Int> {
        var eggs = Triple("달걀", "맥반석", 20230101)
        return eggs
    }
}

Scope Functions

let

  • 블록안 it으로 자신의 객체를 전달하고 수행 결과를 반환
var strNum = "10" 
var result = strNum?.let { // 중괄호 안에서는 it으로 활용함 Integer.parseInt(it) } println(result!!+1)

with

  • this로 자식의 객체를 전달하고 코드 수행결과 반환(this를 생략가능, null이 아닐때만 사용)
	var alphabets = "abcd"

with(alphabets) {
//      var result = this.subSequence(0,2)
    var result = subSequence(0,2)
    println(result)
}

also

  • it으로 자신의 객체를 전달하고 객체자신을 반환(apply와 함께 자주 사용)
var result = student?.also { it.age = 50 }
  • apply : this로 자신의 객체를 전달하고 객체자신을 반환 (주로 객체의 상태를 변화시키고 바로 저장할때 사용)
var result = student?.apply { student.age = 50 }

run

  • this로 접근하고 수행결과를 반환

객체에서 호출하지 않을 때

var totalPrice = run {
	var computer = 10000
	var mouse = 5000
	computer+mouse
}
println("총 가격은 ${totalPrice}입니다")

객체에서 호출할 때 : with와 달리 null체크를 할 수 있어 안전하게 사용가능

student?.run { displayInfo() }
Scope에서 접근방식 thisScope에서 접근방식 it
블록 수행 결과를 반환run, withlet
객체 자신을 반환applyalso

확장함수

  • 기존에 클래스에 쉽게 메소드를 추가할 수 있음
  • 외부에서 클래스의 메소드를 추가한다.
  • 외부에서 관리해 원본클래스의 일관성유지
    • 하위클래스에서 오버라이드 할수없음
    • public멤버에만 접근할 수 있음
fun String.isEmailValid(): Boolean {
    val pattern = "[a-zA-Z0-9._-]+@[a-z]+\\.+[a-z]+"
    return matches(pattern.toRegex())
}

비동기 프로그래밍

  • 순서대로 하나의 작업씩 수행하는 행위를 동기적 프로그래밍이라고 함
  • 비동기 프로그래밍은 요청을 보내고 결과값을 받을 때까지 다른 작업을 수행하기 때문에 여러일을 한번에 수행

쓰레드

  • 쓰레드는 하나의 메인쓰레드(fun main())가 존재
  • thread키워드로 쓰레드를 생성해 동시에 로직을 실행할 수 있음

프로세스와 쓰레드
프로그램을 실행해 메모리에 올라가면 이를 프로세스라고 한다.
프로세스 안에 작업단위를 쓰레드라고 한다.
쓰레드는 각 독립된 메모리영역인 Stack을 가짐

코루틴 종속성추가

Kotlin/kotlinx.coroutines: Library support for Kotlin coroutines (github.com)

dependencies {
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0-RC")
}
fun main() {
    thread(start = true) {
        for(i in 1..10) {
            println("Thread1: 현재 숫자는 ${i}")
            runBlocking {
                launch {
                    delay(1000)
                }
            }
        }
    }

    thread(start = true) {
        for(i in 50..60) {
            println("Thread2: 현재 숫자는 ${i}")
            runBlocking {
                launch {
                    delay(1000)
                }
            }
        }
    }
}

쓰레드를 동시에 시작해서 먼저 실행된 쓰레드의 숫자가 먼저 나오게됨

코루틴

  • 비동기 함수를 제공
  • 쓰레드 보다 가볍게 비동기 프로그래밍을 가능하게 해줌
  • 보통 launch async 를 많이 사용
  • launch는 결과값이 없는 코루틴 빌더이고 Job객체로 코루틴을 관리
  • async는 결과값이 있는 코루틴이고 Deffered타입으로 값을 리턴해줌
  • 코루틴을 실행할 쓰레드를 Dispatcher로 지정 (Dispatcher간 변환이 필요한 경우 withContext를 사용)

GlobalScope: 앱이 실행된 이유에 계속 수행되어야 할 때
CoroutineScope: 필요할때 생성 후 정리가 필요

Dispatchers.Main: UI와 상호작용하기 위한 메인쓰레드
Dispatchers.IO: 네트워크나 디스크 I/O작업에 최적화되어있는 쓰레드
Dispatchers.Default: 기본적으로 CPU최적화되어있는 쓰레드

쓰레드와 코루틴 정리

  • 쓰레드와 코루틴은 둘다 동시성 프로그래밍(비동기)을 위한 기술
  • 동시성 프로그래밍 기술은 컨텍스트 스위칭이 중요한 개념

쓰레드

  • 작업 하나하나의 단위 - Thread
  • 각 Thread가 독립적인 Stack메모리 영역을 가짐
  • 동시성 보장수단 : 운영체제 커널에 의한 context switching

블로킹 (Blocking)
Thread AThread B 결과를 기다릴때 Thread A는 Blocking상태이고 Thread B의 결과가 나올때까지 해당 자원을 사용하지 못함

코루틴

  • 작업 각각에 Object(Coroutine Object)를 할당
  • Coroutine Object도 객체기 때문에 JVM Heap에 적재
  • 동시성 보장수단 : Programmer Switching(NO-Context Switching)
  • 소스코드를 통해 Switching시점을 마음대로 정함
  • 코루틴을 Light-Weight Thread라고 이야기함
    동시처리를 위해 스택영역을 별도로 할당하는 쓰레드처럼 동작하지 않고 동시성을 보장할 수 있으며 하나의 쓰레드에서 다수의 코루틴을 수행하고 커널의 스케쥴링을 따르는 컨텍스트 스위칭을 수행하지 않음

Suspend(Non-Blocking)
Thread A가 Object1을 실행하다가 Object2의 결과를 기다릴 때 Object1은 suspend로 바뀌고 Thread A는 멈추지 않고 다른작업을 수행하다가 Object1이 결과를 다시 받으면 Thread A가 다시 Object1을 수행한다.

profile
편리한 개발자

0개의 댓글

관련 채용 정보

Powered by GraphCDN, the GraphQL CDN