0. 오늘은 무엇을 했는가
오늘은 알고리즘에 시달렸습니다.
정말, 알고리즘 공부가 중요한 것 같습니다.
그렇지만, 평소에 하던 공부도 놓을 수 없어서 안드로이드 공부도 했습니다.
과제가 끝나면... 알고리즘 공부도 시작해야겠습니다.
1. 코드 카타
[ 09:00 ~ 11:00, 14:00 ~ 16:00 ]
오늘의 코드 카타는 피로도 였습니다. 오랜만에 알고리즘을 사용하는 문제였습니다.
사실 이전에도 알고리즘을 사용했어야 했지만 어떻게 넘긴 것도 있겠지만 이번은 넘기기 어려웠습니다.
완전 탐색을 사용한다고 합니다.
사실 이건 뭔지 잘 모르겠지만, 저는 그냥 전부 탐색한다는 의미로 받아들이고 시작했습니다.
처음에는 다음과 같이 작성했습니다.
import java.util.*
class Solution {
fun solution(k: Int, dungeons: Array<IntArray>): Int {
var answer: Int = -1
val firstSize = List<Int>(dungeons.size) { it }
var size = List<Int>(dungeons.size) { it }
var ks = k
var max = 0
var rep = 0
while(true) {
ks = k
answer = 0
for(i in size) {
if(dungeons[i][0] <= ks) {
ks -= dungeons[i][1]
answer++
}
}
if(answer == dungeons.size) return answer
if(max < answer) max = answer
rep++
if(rep == dungeons.size - 1) rep = 0
Collections.swap(size, rep, rep+1)
if(size == firstSize) return max
}
return answer
}
}
위 방식은 Index를 담은 순열을 돌면서 비교해가는 형식이었습니다.
하지만, 모든 Index를 담은 순열이 아니었고, 결과는 2문제가 틀렸습니다.
그래서 저는 이쪽 방향으로 문제를 풀기 위해, 모든 순열을 찾을 수 있는 알고리즘을 찾아봤고,
제가 찾은 알고리즘은 힙 알고리즘 이었습니다.
아래는 해당 알고리즘을 적용해서 만든 코드입니다.
import java.util.*
class Solution {
fun solution(k: Int, dungeons: Array<IntArray>): Int {
var answer: Int = 0
var indices = List<Int>(dungeons.size) { it }
var indCount = MutableList<Int>(dungeons.size) { 0 }
var listIndex = 0
var nowK = k
var nowAnswer = 0
while(dungeons.size > listIndex) {
nowAnswer = 0
nowK = k
if(indCount[listIndex] < listIndex) {
if(listIndex % 2 == 0) Collections.swap(indices, 0, listIndex)
else Collections.swap(indices, indCount[listIndex], listIndex)
for(i in indices) {
if(dungeons[i][0] <= nowK) {
nowK -= dungeons[i][1]
nowAnswer++
}
}
indCount[listIndex]++
listIndex = 0
if(answer < nowAnswer) answer = nowAnswer
}
else {
indCount[listIndex] = 0
listIndex++
}
}
return answer
}
}
이 중 다음 코드가 해당 알고리즘을 구현한 내용입니다.
fun solution(i: Int) {
// i 배열 크기, indices 배열, indCount 배열에 카운트, listIndex 배열의 지금 index
var indices = List<Int>(i) { it }
var indCount = MutableList<Int>(i) { 0 }
var listIndex = 0
// listIndex가 i보다 크면 종료
while(i > listIndex) {
println("$indices | $listIndex | ${indCount[listIndex]}")
// 지금 배열의 카운트가 지금 배열 index보다 작으면
if(indCount[listIndex] < listIndex) {
// 짝수면 0번과 지금 배열 index 자리 교체
if(listIndex % 2 == 0) Collections.swap(indices, 0, listIndex)
// 홀수면 지금 배열 카운트와 지금 배열 index 자리 교체
else Collections.swap(indices, indCount[listIndex], listIndex)
// 지금 배열 카운트 1 더하고 지금 배열은 0으로 초기화
indCount[listIndex]++
listIndex = 0
}
// 지금 배열의 카운트가 지금 배열 index보다 크거나 같으면
else {
// 지금 배열 카운트 0으로 하고 다음 index로 넘어감
indCount[listIndex] = 0
listIndex++
}
}
}
위와 같은 식으로 만들 수 있는 모든 순열들을 만들 수 있습니다.
아직 궁금한 건, 어떻게 모든 순열들이 나올 수 있었을까입니다.
앞으로 여러 알고리즘을 공부하면서 이 궁금증을 풀어야 할 것 같습니다.
2. 안드로이드 공부 및 미니 프로젝트
[ 16:00 ~ 18:00, 19:00 ~ 20:00 ]
오늘 공부한 내용은 모디파이어와 Row, Column입니다.
먼저 Modifier는 어제 말했듯, 컴포저블을 설정해주는 객체라고 보시면 됩니다.
크기, 배경, 클릭 가능 여부 등등을 설정할 수 있습니다.
val modifier = Modifier
위의 경우가 기본적인 형태입니다.
그리고 뒤에다가 확장 함수를 이어붙여서 설정을 추가할 수 있습니다.
Modifier.background().padding().fillMaxSize(). ...
그리고 이미 존재하는 modifier에 다른 modifier 설정을 추가하기 위해선 다음과 같이 할 수 있습니다.
Modifier.then(추가할 모디파이어)
Modifier는 왠만한 컴포저블에는 전부 첫 번째 선택 파라미터로 있습니다.
2-1. Row, Column
Row와 Column은 컴포저블을 가로, 세로로 나열해줍니다.
Row {
//컴포저블 함수들
}
Column {
//컴포저블 함수들
}
뒤에 람다식은 RowScope, ColumnScope로 부르며, 안에 있는 컴포저블들을 나열합니다.
Row와 Column은 Arrangement와 Alignment라는 것이 존재합니다.
Alignment는 조정이라는 뜻이고, Arrangement는 배치라는 뜻입니다.
즉, 나열할 컴포저블을 어떻게 조정하고, 어떻게 배치할 것인지를 정하는 매개변수입니다.
Alignment는 Row와 Column의 방향에 대해 수직적이고, Arrangement는 수평적입니다.
그렇기에 다음과 같이 작성합니다.
Row(verticalAlignment = Alignment.Top, horizontalArrangement = Arrangement.Start)
Column(horizontalAlignment = Alignment.Start, verticalArrangement = Arrangement.Top)
물론 위에 적힌 인자들만 있는 게 아니고, Top, Center, Bottom 등의 인자들도 있습니다.
그리고, Arrangement에는 SpaceEvenly, SpaceBetween 처럼 간격을 조정해 배치하는 방식도 존재합니다.
아직 남은 스코프 모디파이어는 내일 더 공부해서 작성해보겠습니다.
3. 끝
오늘은 이렇게 끝이 났습니다.
사실상 알고리즘을 분석하는 데에만 절반 이상을 쓴 것 같습니다.
하지만, 예전과 달리 코드를 분석하기 시작한 건 정말 좋은 것 같습니다.
끝.