From 25de9d93b0e698a235dfc8530d2f93d59dc10adb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=B0=ED=98=84=EB=B9=88?= Date: Wed, 10 Nov 2021 20:24:35 +0900 Subject: [PATCH] =?UTF-8?q?11=EC=9B=94=2010=EC=9D=BC=20TIL?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plus_one.md" | 66 ++++++ ...5\352\260\200\354\235\264\353\223\2342.md" | 224 ++++++++++++++++++ 2 files changed, 290 insertions(+) create mode 100644 "\354\225\214\352\263\240\353\246\254\354\246\230/plus_one.md" create mode 100644 "\354\275\224\353\243\250\355\213\264/\354\275\224\353\243\250\355\213\264 \352\263\265\354\213\235\352\260\200\354\235\264\353\223\2342.md" diff --git "a/\354\225\214\352\263\240\353\246\254\354\246\230/plus_one.md" "b/\354\225\214\352\263\240\353\246\254\354\246\230/plus_one.md" new file mode 100644 index 0000000..083e6ea --- /dev/null +++ "b/\354\225\214\352\263\240\353\246\254\354\246\230/plus_one.md" @@ -0,0 +1,66 @@ +# Plus One + +You are given a **large integer** represented as an integer array `digits`, where each `digits[i]` is the `ith` digit of the integer. The digits are ordered from most significant to least significant in left-to-right order. The large integer does not contain any leading `0`'s. + +Increment the large integer by one and return the resulting array of digits. + +## Example 1: +``` +Input: digits = [1,2,3] +Output: [1,2,4] +Explanation: The array represents the integer 123. +Incrementing by one gives 123 + 1 = 124. +Thus, the result should be [1,2,4]. +``` + +## Example 2: +``` +Input: digits = [4,3,2,1] +Output: [4,3,2,2] +Explanation: The array represents the integer 4321. +Incrementing by one gives 4321 + 1 = 4322. +Thus, the result should be [4,3,2,2]. +``` + +## Example 3: +``` +Input: digits = [0] +Output: [1] +Explanation: The array represents the integer 0. +Incrementing by one gives 0 + 1 = 1. +Thus, the result should be [1]. +``` + +## Example 4: +``` +Input: digits = [9] +Output: [1,0] +Explanation: The array represents the integer 9. +Incrementing by one gives 9 + 1 = 10. +Thus, the result should be [1,0]. +``` + +## 풀이 +```kotlin +class Solution { + fun plusOne(digits: IntArray): IntArray { + var carry = 1 + var index = digits.size - 1 + var result: IntArray = digits + + while(index >= 0 && carry > 0) { + result[index] = (result[index] + 1) % 10 + carry = if(result[index] == 0) 1 else 0 + + index-- + } + + if(carry > 0) { + result = IntArray(digits.size + 1) + result[0] = 1 + } + + return result + } +} +``` \ No newline at end of file diff --git "a/\354\275\224\353\243\250\355\213\264/\354\275\224\353\243\250\355\213\264 \352\263\265\354\213\235\352\260\200\354\235\264\353\223\2342.md" "b/\354\275\224\353\243\250\355\213\264/\354\275\224\353\243\250\355\213\264 \352\263\265\354\213\235\352\260\200\354\235\264\353\223\2342.md" new file mode 100644 index 0000000..577cbf9 --- /dev/null +++ "b/\354\275\224\353\243\250\355\213\264/\354\275\224\353\243\250\355\213\264 \352\263\265\354\213\235\352\260\200\354\235\264\353\223\2342.md" @@ -0,0 +1,224 @@ +# 코틀린 공식 가이드 2 + +## 취소(Cancellation) +* 코루틴에서 실행되는 모든 중단 함수 (`suspending function`)들은 취소 요청에 응답 가능하도록 구현되어야 함. +* 중단 함수는 실행 중 취소 가능한 구간마다 취소 요청이 있었는지 확인하고 요청이 있었다면 실행을 즉시 취소하도록 구현해야 함. +* `kotlinx.coroutines` 라이브러리의 모든 중단함수는 이러한 취소 요청에 대응하도록 구현되어있음. +* 취소를 지원하는 중단 함수들은 실행하는 동안 취소가 가능한 지점마다 현재 코루틴이 취소 되었는지 확인하며, 만약 취소되었다면 `CancellationException`을 발생시키며 종료함. + +> ReactiveX Observable을 구현해 본 경험이 있는 사람이라면 Observable의 코드 실행 중 취소 가능한 구간마다 isDisposed() 같은 취소 상태 확인 함수를 이용하여 현재 Observable의 구독 취소 여부를 확인하고 Observable의 데이터 방출을 정지하고 종료해야 하는지 판단해본 기억이 있을 것입니다. + +* 만약 다음과 같이 코루틴을 작성하면 취소 요청이 오더라도 작업을 멈추지 않고 계속 진행함 (`Sleep` 대신 `Busy-waiting` 구현을 해도 마찬가지) + +```kotlin +fun main(args: Array) = runBlocking { + val job = launch(Dispatchers.Default) { + for(i in 1..10) { + println("I'm sleeping $i ...") + Thread.sleep(500L) + } + } + + delay(1300L) + println("main: I'm tired of waiting!") + job.cancelAndJoin() + println("main: Now I can quit.") +} +``` + +* 이 코루틴을 취소 요청에 친화적인 코드로 만들기 위해서는 취소가 가능한 시점마다 다른 `Continuation`에 실행 시간을 양보하는 `yield()` 함수를 호출하거나 +* `CoroutineScope`에 정의된 `isActive` 속성을 참조하여 코루틴이 비활성 상태인 경우 작업을 중단하도록 하는 방법이 있음. + +### yield() 중단함수를 사용한 구현 + +```kotlin +fun main(args: Array) = runBlocking { + val job = launch(Dispatchers.Default) { + for(i in 1..10) { + yield() + println("I'm sleeping $i ...") + Thread.sleep(500L) + } + } + + delay(1300L) + println("main: I'm tired of waiting!") + job.cancelAndJoin() + println("main: Now I can quit.") +} +``` + +### isActive를 이용한 구현 + +```kotlin +fun main(args: Array) = runBlocking { + val job = launch(Dispatchers.Default) { + for(i in 1..10) { + if(!isActive) { + break + } + println("I'm sleeping $i ...") + Thread.sleep(500L) + } + } + + delay(1300L) + println("main: I'm tired of waiting!") + job.cancelAndJoin() + println("main: Now I can quit.") +} +``` + +* 취소가 가능한 중단함수들은 췻되면 `CancellationException`을 발생시킴 +* 우리는 일반적인 예외처리 방식과 동일하게 이를 처리할 수 있음. +* 만약 예외발생시 해제 해야할 리소스가 있다면 + * `try~finally` 구문을 사용 + * `use()` 함수를 사용 +* 두 가지 방법으로 해결할 수 있음. + +### try ~ finally를 사용한 구현 +```kotlin +fun main(args: Array) = runBlocking { + val job = launch(Dispatchers.Default) { + try { + repeat(1000) { i-> + println("I'm sleeping $i ...") + delay(500L) + } + } finally { + println("main : I'm running finally!") + } + } + + delay(1300L) + println("main: I'm tired of waiting!") + job.cancelAndJoin() + println("main: Now I can quit.") +} +``` + +### use() 메소드를 이용한 구현 +```kotlin +fun main(args: Array) = runBlocking { + val job = launch { + SleepingBed().use { + it.sleep(1000) + } + } + + delay(1300L) + println("main : I'm tired of waiting!") + job.cancelAndJoin() + println("main : Now I can quit.") +} + +class SleepingBed : Closeable { + + suspend fun sleep(times: Int) { + repeat(times) { i -> + println("I'm sleeping $i ...") + delay(500L) + } + } + + override fun close() { + println("main : I'm running close() in SleepingBed!") + } + +} +``` + +## 취소 불가능한 코드 블럭의 실행 (Run non-cancellable block) +* 이미 `CancellableException`이 발생한 코루틴의 `finally` 블록 안에서 중단 함수를 호출하면 현재 코루틴은 이미 취소된 상태이기 때문에 `CancellationException`이 발생함. +* 보통 리소스를 정리하는 함수들은 논-블록킹으로 동작하기 때문에 이러한 제약이 큰 문제가 되지는 않음. +* 이미 취소된 코루틴 안에서 동기적으로 어떤 중단 함수를 호출해야 하는 상황이라면 `withContext{ }` 코루틴 빌더에 `NonCanecllable` 컨텍스트를 전달하여 이를 처리할 수 있음. + +```kotlin +fun main(args: Array) = runBlocking { + val job = launch { + try { + repeat(1000) { i -> + println("I'm sleeping $i ...") + delay(500L) + } + } finally { + withContext(NonCancellable) { + delay(1000) + println("main : I'm running finally!") + } + } + } + + delay(1300L) + println("main : I'm tired of waiting!") + job.cancelAndJoin() + println("main : Now I can quit.") +} +``` + + +## 타임아웃 (Timeout) +* 일반적으로 어떤 코루틴의 실행을 중간에 취소해야 하는 경우는 그 수행시간이 너무 길어져 허용할 수 있는 시간을 넘어섰을 경우 +* 이 경우 우리는 타임아웃을 지정하고 이 시간을 넘어설 경우 해당 작업을 취소하도록 구현할 수 있음. +* 일반적으로 취소 요청이 없었음에도 어떤 코루틴의 실행을 중간에 취소해야 하는 경우는 그 코루틴의 수행시간이 허용 가능한 시간보다 길어졌을 경우. +* 이러한 경우를 다루기 위해서 우리는 코루틴에 제한 시간 (`Timeout`)을 설정하고 이 시간이 넘어설 경우 코루틴을 취소되도록 구현할 수 있음. + +1. 제한 시간을 설정 할 대상이 되는 코루틴을 생성. +2. 일정 시간 (Timeout) 지연 후 전달받은 `job`이 끝나지 않았으면 취소하는 동작을 하는 코루틴을 생성하고, 1번에서 만들고 실행한 코루틴의 `job` 객체를 전달함. +3. 테스트를 위해 1번 코루틴은 2번 코루틴에서 설정한 시간보다 긴 수행시간을 갖도록 구현함. + +```kotlin +fun main(args: Array) = runBlocking { + val job = launch { + try { + repeat(1000) { i -> + println("I'm sleeping $i ...") + delay(500L) + } + } finally { + println("main : I'm running finally!") + } + } + + launch { + delay(1300L) + println("main : I'm tired of waiting. Cancel the job!") + if (job.isActive) { + job.cancelAndJoin() + } + } +} +``` + +* 위 구현은 우리가 예상한대로 동작함. +* 하지만 매번 Job 객체 참조를 유지하면서 별도의 코루틴에서 취소 하도록 하는 것은 번거롭기 때문에 이 경우 보통 `withTimeout()` 함수를 사용함. + +```kotlin +fun main(args: Array) = runBlocking { + withTimeout(1300L) { + launch { + try { + repeat(1000) { i -> + println("I'm sleeping $i ...") + delay(500L) + } + } finally { + println("main : I'm running finally") + } + } + } +} +``` + +* 위 함수를 실행하면 `TimeoutCancellationException`이 발생 +* 이는 예제가 메인 함수에서 바로 실행되었기 때문. +* 코루틴이 취소될 경우 발생하는 `CancellationException`은 코루틴에서 일반적인 종료 상항 중 하나로 간주됨. + +``` +I’m sleeping 0 … +I’m sleeping 1 … +I’m sleeping 2 … +main : I’m running finally! +Exception in thread “main” kotlinx.coroutines.TimeoutCancellationException: Timed out waiting for 1300 ms at kotlinx.coroutines.TimeoutKt.TimeoutCancellationException(Timeout.kt:122) at kotlinx.coroutines.TimeoutCoroutine.run(Timeout.kt:88) +Process finished with exit code 1 +``` \ No newline at end of file