오늘 공부한 내용 정리(2024년 7월 16일)
코드카타 문제풀이
토마토(Gold 5, 7576번)
문제 내용
문제 풀이 방법
창고에 보관된 M x N 크기의 상자에 익은 토마토(1), 안 익은 토마토(0) 빈 곳(-1)이 입력으로 주어질 때, 토마토가 모두 익을 때까지의 최소 날짜를 출력
토마토는 익은 토마토가 있는 곳의 상하좌우에 안 익은 토마토가 있으면 그 토마토가 익은 토마토가 된다.
해결 코드(스포 주의)
import java.io.BufferedReader
import java.io.InputStreamReader
import java.util.ArrayDeque
private var box = arrayOf<MutableList<Int>>()
private var findDay = 0
private val queue = ArrayDeque<List<Int>>()
private val dx = listOf(-1, 1, 0, 0)
private val dy = listOf(0, 0, -1, 1)
fun main() = with(BufferedReader(InputStreamReader(System.`in`))) {
val (width, height) = readLine().split(" ").map { it.toInt() }
box = Array(height) { mutableListOf() }
for (i in 0 until height) {
val input = readLine().split(" ").map { it.toInt() }
box[i].addAll(input)
for (j in input.indices) {
if (box[i][j] == 1) {
queue.add(listOf(i, j, 0))
}
}
}
bfs()
for (i in box.indices) {
if (box[i].contains(0)) {
findDay = -1
break
}
}
println(findDay)
}
private fun bfs() {
while (queue.isNotEmpty()) {
val data = queue.removeLast()
findDay = data[2]
findData(data[0], data[1])
}
}
private fun findData(h: Int, w: Int) {
for (i in dx.indices) {
val mw = w + dx[i]
val mh = h + dy[i]
if (mw in box[0].indices && mh in box.indices) {
if (box[mh][mw] == 0) {
box[mh][mw] = 1
queue.addFirst(listOf(mh, mw, findDay + 1))
}
}
}
풀이 과정
상자 정보를 저장할 box 변수를 생성한다.
찾을 날짜인 findDay 변수를 생성한다.
익은 토마토의 위치 정보(x, y)와 해당 토마토가 익은 날짜가 함께 들어갈 큐(ArrayDeque)를 만들어 준다.
dx, dy는 기준점에서 상하좌우의 데이터를 확인하기 위함이다.
width, height를 입력받고 box를 초기화해 준다.
초기에 입력받는 값들 중 1이 들어 있는 곳의 index 정보와 0을 함께 리스트에 넣어서 큐에 넣어 준다.
그리고 bfs() 함수를 수행한다
bfs()에서는 큐의 값이 빌 때까지 반복한다.
큐에서 뽑은 데이터의 값에서 2번째 index에 해당하는 값을 findDay로 설정해 준다.
그리고 findData()로 상하좌우의 값을 확인해 덜 익은 토마토(0)이면 1로 변경해 주고, 큐의 맨 앞에 넣어준다(날짜는 findDay의 +1을 한 값으로).
반복이 끝나고 마지막 값의 날짜를 출력한다.
문제 해결 과정
원래는 Queue를 사용하는 방법이지만, ArrayDeque로 구현해 주었다.
Queue는 선입선출이라 0일 차의 토마토가 여러 개이면 해당 일차의 토마토를 모두 보기 전에 다른 일차의 데이터가 들어와서 값이 꼬일 수 있어서 ArrayDeque를 사용해 주었다.
bfs를 이용하면서 시간 초과를 고려해야 하는 문제이다.
큐에 값의 위치 index와 일차 정보를 같이 담는 아이디어를 내지 못하면 힘들 수도 있는 문제이다.
수준별 학습반 과제
TabLayout + ViewPager2를 이용한 탭 화면 구성.
공부 내용 간단 정리
이전에 화면 구성을 Activity -> Fragment(bottom navigation) -> Fragment(tab) 순으로 구성해 주었다.
viewPager가 있는 게 나을 것 같아서 tab xml의 UI를 일부 수정해 주었다.
TabLayout과 ViewPager2를 같이 작성해 준다.
나중에 두 개를 서로 연결하고 나면 Tab이 바뀜에 따라 ViewPager2 영역에 보이는 Fragment가 달라질 것이다.
다음으로는 ViewPager2의 Adapter를 생성해 준다.
class GameViewPager2Adapter(activity: FragmentActivity): FragmentStateAdapter(activity) {
override fun getItemCount(): Int = 6
override fun createFragment(position: Int): Fragment = when (position) {
0 -> RecommendFragment()
1 -> PopularChartFragment()
else -> SoonFragment()
}
}
첫 번째(추천)와 두 번째(인기 차트)를 제외한 나머지 탭은 구현하지 않을 것이기 때문에 SoonFragment()로 설정해 준다.
getItemCount에는 tabLayout에 쓸 tab의 개수를 return 해준다.
마지막으로 title을 저장한 list를 생성해 주고, TabLayoutMediator를 이용해 ViewPager2와 연결한다.
with(binding) {
val tabTitle = listOf("추천", "인기 차트", "키즈", "신규", "프리미엄", "카테고리")
gameViewPager2.adapter = GameViewPager2Adapter(requireActivity())
TabLayoutMediator(gameLayoutCategoryTab, gameViewPager2) { tab, pos ->
tab.text = tabTitle[pos]
}.attach()
}
attach()를 써주지 않으면 TabLayout의 Tab이 보이지 않게 되는 오류가 발생하므로 주의.
인기 차트 화면 구성
다음으로는 예전에 구현한 인기 차트 화면의 데이터를 RecyclerView로 갈아 주는 작업을 해준다.
오늘을 기준으로 인기 차트에 이름이 올라가 있는 앱 상위 20개를 불러와 데이터를 만들어 주고, RecyclerView를 써서 앱에 띄워 주었다.
이 부분은 어렵지 않으므로 코드 말고 결과 사진을 첨부한다.
상단의 Tab은 ViewPager와 연결돼 있어서 가로 스크롤로 tab끼리 이동할 수 있다.
오늘 공부 내용 정리 및 회고
오늘 이상한 데 헛손질하느라 시간을 꽤 많이 잡아먹어서 많이 구현하지는 못했다.
헛손질한 부분은 TabLayout을 구현하고(viewPager 없이) tab을 클릭해서 화면 전환을 테스트하는 중에 이미 구현이 완료된 인기 차트 탭을 누를 때마다 TabLayout의 indicator가 부자연스럽게 움직였다.
왜 그런 건지는 아직도 이유를 찾지 못했다. viewPager2까지 연결해 주니까 좀 덜해지긴 했다.
내일은 추천 화면을 여러 개의 ViewType을 이용해 구현해 보겠다.
'♞ | 공부일지 > ♝ | TIL' 카테고리의 다른 글
[Android, 내일배움캠프] 공부일지(2024-07-18) (0) | 2024.07.18 |
---|---|
[Android, 내일배움캠프] 공부일지(2024-07-17) (2) | 2024.07.17 |
[Android, 내일배움캠프] 공부일지(2024-07-15) (0) | 2024.07.15 |
[Android, 내일배움캠프] 공부일지(2024-07-12) (0) | 2024.07.12 |
[Android, 내일배움캠프] 공부일지(2024-07-11) (0) | 2024.07.11 |