티스토리 뷰

코드카타

 

숫자 변환하기

 

문제

 

 

입출력 예시

 

x를 y로 만드는 최소 횟수를 구하는 문제이므로 bfs의 개념을 활용해야 한다.

 

 

풀이

import java.util.*

class Solution {
    fun solution(x: Int, y: Int, n: Int): Int {
    	// 큐와 방문표시를 선언하고 초기값 설정
        val q = LinkedList(listOf(Pair(x, 0)))
        val v = mutableListOf(x)
		
        // 너비 우선 탐색
        while (q.isNotEmpty()) {
            // 각 변수는 현재 탐색 중인 노드, 연산 횟수에 해당함
            val (current, res) = q.remove() 
			
            // 주어진 시작노드와 목표 노드가 같은 값일 때의 처리
            if (current == y) return res
			
            // 다음에 탐색할 노드들을 리스트로 생성
            val next = listOf(current + n, current * 2, current * 3)
			
            // 각 노드에 대해 탐색 진행
            for (i in next) {
            	// 목표 노드에 도달했을 경우 (현재 연산횟수 + 1)을 반환하고 종료
                if (i == y) return res + 1
                
                // 현재 노드가 목표 노드보다 작고, 방문하지 않은 노드라면 큐에 추가
                // 목표 노드보다 큰 값을 가진 노드는 탐색하지 않음으로써 실행시간을 줄임 
                if (i < y && i !in v) {
                    v.add(i) // 탐색한 노드 방문 기록 추가 후
                    q.add(Pair(i, res + 1)) // 큐에 새로운 값을 추가
                }
            }
        }
		
        // 큐를 모두 탐색한 후 목표 노드에 도달하지 못했을 경우 -1 반환
        return -1
    }
}

BFS(너비 우선 탐색) 알고리즘을 활용하여

시작 노드 x에서 목표 노드 y까지의 최단 거리를 계산한다.

 

다음에 탐색할 노드들을 생성해 너비 우선적으로 탐색을 진행하며

방문 기록을 통해 중복 생성을 방지해 시간 복잡도를 줄인다.

 

 

큐 초기값 설정

val q = LinkedList(listOf(Pair(x, 0)))

LinkedList는 생성자로 Collection을 받기 때문에
data class에 해당하는 Pair를 넣는 것은 불가능하다.

LinkedList의 초기값에 Pair를 넣으러면 Pair를 리스트로 감싸서 
Collection자료형을 linkedList 생성자에 전달해줘야한다.

 

 

큐 요소의 자료형

val q = LinkedList(listOf(10, 0))
val (a, b) = q.remove() // 런타임 에러

LinkedList의 생성자에 List<Int>형 값을 넘기게 되면

해당 요소는 LinkedList<Int>형으로 변환된다.

 

해당 구문에서 q.remove()는 Int 타입의 요소 하나를 반환하기에

복합 타입 요소를 반환해야하는 구조분해선언이 불가하게 된다.

 

 

BFS란?

BFS(너비 우선 탐색 알고리즘)은 시작 노드에서

목표 노드까지의 최단 경로를 찾기 위해 사용되는 알고리즘이다.

 

BFS 시작 노드에 인접한 모든 노드들을 탐색한 뒤,

그 다음 레벨을 탐색하는 방식으로 최단경로를 찾는다.

 

BFS는 각 노드에 인접한 노드들을 다음 탐색후보로써 큐에 추가한다.

 

방문한 노드는 방문기록을 통해 중복 탐색을 방지한다.

 

 

회고

너비우선탐색의 구현방식과 개념을 알게되었다.

몰랐던 큐의 특징을 공부할 수 있었다.

 


 

툴바 생성하기

 

toolbar.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:padding="12dp"
    >

    <ImageView
        android:id="@+id/iv_left_icon"
        android:paddingStart="8dp"
        android:layout_width="wrap_content"
        android:layout_height="48dp"
        android:src="@drawable/logo"/>

    <Button
        android:id="@+id/btn_login"
        android:layout_width="100dp"
        android:layout_height="48dp"
        android:text="로그인"
        android:textColor="@color/gray"
        android:backgroundTint="@color/light_pink"
        android:layout_alignParentRight="true"
        />

    <TextView
        android:visibility="gone"
        android:id="@+id/tv_user_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toLeftOf="@id/iv_right_icon"
        android:layout_centerVertical="true"

        android:text="OO님"
        android:paddingEnd="8dp"/>

    <ImageView
        android:visibility="gone"
        android:layout_centerVertical="true"
        android:id="@+id/iv_right_icon"
        android:paddingEnd="4dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:src="@drawable/account_circle"/>

</RelativeLayout>

res/drawable/layout 폴더에 toolbar.xml을 추가한다.

 

레이아웃 위젯에 전체적으로 패딩값을 12dp 정도 준다.

RelativeLayout으로 상대적인 위치에 따라 뷰들을 배치해준다.

 

기본적으로는 로그인 버튼만 보이는 상태이며 

로그인 진행시 버튼은 숨겨지고 계정 아이콘과 닉네임이 보이게된다.

 

 

앱바 추가

<include
    android:id="@+id/toolbar"
    layout="@layout/toolbar" />

정의해둔 앱바는 include로 가져온다.

 

 

앱바 초기화 함수

 

메인화면과 디테일 화면에서는 로그인 여부에 따라 앱바가 바뀌게 된다.

 

private fun initToolBar() {
        val accountIcon = findViewById<ImageView>(R.id.iv_right_icon)
        val userName = findViewById<TextView>(R.id.tv_user_name)
        val loginBtn = findViewById<Button>(R.id.btn_login)

        // 로그인 확인 조건문(임시)
        if(false) {
            loginBtn.setVisibility(View.GONE);
        }else{
            accountIcon.setVisibility(View.GONE)
            userName.setVisibility(View.GONE)
        }

        loginBtn.setOnClickListener {
            val intent = Intent(this, SignInActivity::class.java)
            startActivity(intent)
        }
    }

툴바의 뷰를 변수에 저장해 아이콘이나 버튼을 눌렀을 때의 동작을 지정한다.

로그인 여부에 따라 좌측에 다른 아이콘이 보이도록 하는 로직을 임시로 작성해준다.

 

leftIcon.setImageResource(R.drawable.back)
leftIcon.setOnClickListener {
    finish()
}

 

 

디테일 화면에서는 앱바의 왼쪽 이미지를 가져와 뒤로가기 아이콘으로

바꾸고 해당 아이콘의 뒤로가기 동작을 정의구문을 추가한다.

 

 

MaterialToolbar

뒤로가기만을 포함하는 간단한 앱바이다.

 

<com.google.android.material.appbar.MaterialToolbar
        android:id="@+id/toolbar_signin"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:navigationIcon="@drawable/back" />

이거는 팀원분이 MaterailToolbar를 이용해서 만들어놨다.

 

private fun initToolbar(){
    val toolbar = findViewById<MaterialToolbar>(R.id.toolbar_signup)
    setSupportActionBar(toolbar)
    supportActionBar?.title = ""
    toolbar.setNavigationOnClickListener {
        finish()
    }
}

만들어둔 툴바를 현재 화면의 툴바로 설정하고

툴바의 제목과 뒤로가기 아이콘 동작을 정의한다.

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/11   »
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
글 보관함