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

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

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

 

출처: unsplash.com

 

코드카타 문제풀이

최소공배수(Bronze 1, 1934번, 마라톤)

문제 내용

 

문제 풀이 방법

두 수 A, B가 주어질 때, 두 수의 최소공배수를 출력한다.

최소공배수를 구하는 방법은 여러 가지가 있지만, 나는 유클리드 호제법을 이용해 최대공약수를 구하고, 최대공약수와 최소공배수의 관계를 이용해 최소공배수를 구할 것이다.

 

 

해결 코드(스포 주의)

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

fun main() = with(BufferedReader(InputStreamReader(System.`in`))){
    val case = readLine().toInt()

    for (i in 0 until case) {
        val (a, b) = readLine().split(" ").map { it.toInt() }
        var gcdA = a
        var gcdB = b

        while (gcdB != 0) {
            val res = gcdA % gcdB
            gcdA = gcdB
            gcdB = res
        }

        println(a * b / gcdA)
    }
}

 

풀이 과정

A, B를 입력받은 case만큼 반복한다.

a, b를 입력받고 최소공배수용 A(gcdA)와 B(gcdB)를 만들어 준다.

 

gcdB가 0이 될 때까지 반복해 준다.

반복문 안에는 유클리드 호제법 공식을 적용해 준다.

 

gcdB가 0이 돼서 반복이 끝나면 gcdA가 최대공약수가 된다.

최대공약수와 최소공배수는 다음과 같은 공식을 만족한다.

a * b = 최대공약수 * 최소공배수

a: 6이고 b: 10일 때 최대공약수는 2이다.

60 = 2 * 최소공배수를 만족하기 때문에 최소공배수는 30이다.

실제로 계산해 보면 정말로 최소공배수로 30이 나올 것이다.

 

 

문제 해결 과정

유클리드 호제법과 최대공약수와 최소공배수의 관계를 이해하면 쉽게 구할 수 있는 문제.

유클리드 호제법이 최대공약수용 알고리즘이라 자주 쓰이지가 않아서 자료를 한 번 찾아보고 해결했다.

 

 

알고리즘 수업 - 선택 정렬 5(Bronze 1, 23899번, 마라톤)

문제 내용

 

문제 풀이 방법

배열의 크기인 N을 입력받고 정렬을 시작할 배열 A와 정렬되고 있는 배열 A와 비교할 배열 B를 입력받는다.

A를 선택 정렬을 진행하면서 B와 같아지면 1을 출력하고, 아니면 0을 출력한다.

 

 

해결 코드(스포 주의)

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

private var size = 0
private var array: Array<Int> = arrayOf()
private var duringArray: Array<Int> = arrayOf()
private var result = 0

fun main() = with(BufferedReader(InputStreamReader(System.`in`))) {
    size = readLine().toInt()
    val arrayA = StringTokenizer(readLine())
    val arrayB = StringTokenizer(readLine())

    array = Array(size + 1) { 0 }
    duringArray = Array(size + 1) { 0 }
    for (i in 1 .. size) {
        array[i] = arrayA.nextToken().toInt()
        duringArray[i] = arrayB.nextToken().toInt()
    }

    if (array.contentEquals(duringArray)) println(1)
    else {
        selectionSort()
        println(result)
    }
}

private fun selectionSort() {
    for (last in size downTo 2) {
        var maxValue = 0
        var indexMax = last
        for (j in 1 .. last) {
            if (maxValue < array[j]) {
                maxValue = array[j]
                indexMax = j
            }
        }

        if (indexMax != last) {
            val temp = array[indexMax]
            array[indexMax] = array[last]
            array[last] = temp
        }

        if (array.contentEquals(duringArray)) {
            result = 1
            break
        }
    }
}

 

풀이 과정

배열의 크기인 size를 생성해 입력받고, 정렬을 진행할 배열 array와 정렬 중인 array와 값을 비교할 duringArray를 생성한다.

array와 duringArray의 길이를 size + 1로 초기화한다(0번째 index를 안 쓰기 위함).

입력받은 값들을 모두 array들에 넣어 준다.

 

그리고 초반에 array와 duringArray가 같은지 확인한다.

같으면 정렬을 할 필요 없이 1을 출력하고 끝내면 된다.

조건을 만족하지 않으면 selectionSort()를 수행한다.

 

array의 size부터 2까지 뒤로 가도록 반복한다.

먼저 최댓값의 index를 찾아야 한다.

반복을 진행할수록 범위가 점점 좁아진다(1.. 5 -> 1.. 4).

1부터 last까지 반복한다.

최댓값인 maxValue가 array의 j번째 값보다 작으면 최댓값을 갱신시키고 최댓값의 인덱스값인 maxIndex를 j로 변경한다.

 

최댓값을 구한 후, 최댓값의 index값과 마지막 값이 다르다면 서로의 값을 교환한다.

교환 후 duringArray와 같은지 확인해 준다. 같으면 result를 1로 바꾸고 반복을 종료한다.

 

함수 수행 후 result를 출력한다.

 

 

문제 해결 과정

선택 정렬 구현은 어렵지 않았지만, 처음에 입력받을 때부터 같은 값이 입력되는 경우를 고려하지 않아서 74%에서 틀렸었다.

10번 정도 실패하고 검색으로 풀이를 찾아봐서 문제를 알게 되었다.

 

 

수준별 학습반 4주 차(standard class)

Fragment(4주 차)

활동 내용 간단 정리

Fragment는 여러 개의 화면을 구성하는 방법에서 쓸 수 있는 방법이다.

Fragment를 사용하지 않고 Activity로만으로도 화면을 구성할 수는 있다.

 

여러 개의 Activity를 만들다 보면 다음과 같은 단점이 생긴다.

성능이 느려진다.
Data 공유가 어려워진다.
Bottom navigation과의 연결이 부자연스럽다.

 

하지만 Fragment로 구성하면 다음과 같은 장점이 있다.

반복되는 화면은 재사용이 가능하다
Activity를 매번 Create, Destroy 하지 않아도 된다.
UI만 교체하기 때문에 성능도 향상된다.
각 화면 간의 데이터 공유가 쉬움.
Bottom Navigation과의 연결이 자연스러워진다.

 

Fragment: 앱의 UI의 일부를 나타내는 재사용 가능한 클래스이다.

하나의 Fragment를 여러 개의 Activity에서 재사용할 수 있다.

 

Fragment를 굳이 써야 할까?

재사용성: 다양한 Activity에서 쓸 수 있다.
모듈성: 복잡한 UI를 여러 개의 작은 단위로 나눠서 효율적으로 관리한다.
유연한 UI: 하나의 Activity에서 여러 Fragment를 교체하거나 함께 표시하면서 다양한 화면 크기와 방향에 맞는 유연한 사용자 인터페이스 제공
독립적인 라이프사이클: Fragment는 자체 lifeCycle을 가지고 있어서, Activity의 lifeCycle과 따로 독립적으로 관리해서 앱의 안정성을 높인다.
성능: 필요할 때만 load 되고 제거될 수 있어서, 메모리를 아낄 수 있다.

 

Fragment의 LifeCycle

 

 

 

수준별 학습반 개인 과제(앱 업그레이드 v2, standard class)

앱 업그레이드 v2 완료.

공부 내용 간단 정리

v2에서 마지막 남은 요구 사항인 RecyclerView에 multi ViewType을 사용하는 것이다.나는 추천 화면을 만들어서 이벤트 앱과, 헤더, 스폰서/프리미엄 앱 총 4개의 item을 이용해 Adapter를 구성할 것이다.

각각의 item에는 각각 다른 data class 데이터가 필요하다.

그래서 sealed class를 만들어서 그 안에 data class를 만들어 주었다(코드는 분량상 스킵).

 

Header와 EventAppData를 제외하고 나머지 2개의 데이터는 하위에 RecyclerView를 구성해야 한다.

그래서 sealed class 내부에 만든 데이터 클래스 데이터에 리스트 타입으로 쓰일 데이터 클래스를 다시 구성해주어야 한다.

sealed class RecommendData: Parcelable {
    @Parcelize
    data class SponsorAppDataList(
        val id: Int,
        val list: List<SponsorAppData>
    ): RecommendData()
}

@Parcelize
data class SponsorAppData(
    val id: Int,
    val appIcon: Int = 0,
    val title: String = "",
    val category: String = "",
    val starRating: Double = 0.0,
    val link: String = ""
): Parcelable

아래 코드와 같이 하위 데이터 클래스는 따로 만들어 준다.

 

Adapter를 만드는 방법은 기존 Adapter를 만드는 것과 다른 건 없지만 타입에 따라 ViewHolder를 각각 설정해 주어야 한다.

onCreateViewHolder에서는 viewType에 따라 각각 다른 item xml의 binding을 넣어 주고,

onBindViewHolder에서는 getItem()의 타입에 따라 ViewHolder의 bind를 각각 수행한다(코드 없음).

 

간단하게 설명이 끝났으니, 실행 결과를 봐보자.

 

현재 총 3종류의 아이템이 보인다.

헤더: 스폰서, 컨트롤러로 플레이하기
이벤트: 마인크래프트
스폰서: 스폰서 앱 9종류(3종류씩 3번, Grid + Horizontal 사용)

더 많은 정보는 수준별 학습반 노션에 적어 놓겠다.

 


 

오늘 공부 내용 정리 및 회고

수준별 학습반 v2 과제를 모두 끝냈다.

내일부터는 바로 v3 과제를 시작할 것이다.

클론 앱에 애착이 생기는 걸까? 계속 앱에 살을 붙이고 싶은 욕심이 들어서 개발 완료 시간이 늦어진다 ㅋㅋ;

728x90