✏20231211 월요일
- 배열의 첫번째(인덱스0번)는 물 한개. 이므로 1칼로리음식(인덱스1번)부터 계산할 수 있게 반복문 범위를 설정했다.
- 각 칼로리 음식에 대하여 2명이 공평하게 나눌 수있도록 나누기2를 한 만큼 repeat()으로 반복될 수 있도록 했다.
- 오른쪽 선수의 음식들에 더해서 가운데에 물(0칼로리)를 두고, 왼쪽 선수도 낮은칼로리의 음식부터 먹을 수 있도록 refversed()를 사용하여 반환해주었다.
class Solution {
fun solution(food: IntArray): String {
var answer: String = ""
for(i in 1 until food.size){
answer += i.toString().repeat(food[i]/2)
}
return answer + "0" + answer.reversed()
}
}
- expression 'size' of type 'Int' cannot be invoked as a function. The function 'invoke()' is not found 오류
=>size쓸때 아무생각없이 ( )괄호를 붙였다가 오류를 만났다. size는 ( )괄호없이 속성방식으로 사용해야 한다.
- repeat(n:Int)함수는 int타입을 인자로 받지만, 내부적으로 StringBuilder를 사용하기때문에 문자열에만 사용할 수 있다. for문에서 숫자로 진행되는 i에 대해 toString()을 써서 문자열로 인식할 수 있도록 바꿔주어야 오류가 나지 않는다.
- 배열에서 reversed( )를 쓰면 리스트로 반환하는데, 여기서 사용한 reversed( )는 String자체에 내장된 reversed( )메소드 이다. 그래서 문자열에서 사용해서 그대로 문자열을 반환해준다.
- val n 값을 받을, bottle을 변수로 선언했다. 개수에 맞게 교환하고 남는 나머지들의 값을 저장하기 위해 empty변수를 만들었다. 마지막으로 교환가능한 병 개수의 값을 저장하기 위한 change를 만들었다.
- change(교환가능한 병의 전체 수)가 a(최소 교환 가능 개수) 보다 크거나 같을(교환가능) 동안 while문이 반복되도록 작성했다.
- 반복문 안에서 받을 수 있는 콜라의 수를 bottle에 저장하고, answer에 총 교환 콜라 수를 누적 합산 하도록 해서, answer를 return했다.
class Solution {
fun solution(a: Int, b: Int, n: Int): Int {
var answer: Int = 0
var bottle = n
var empty = 0
var change = bottle + empty
while(change >= a) {
bottle = change/a * b
empty = change % a
change = bottle + empty
answer += bottle
}
return answer
}
}
- while반복문 쓸 때.. 자꾸.. 범위 설정하는걸 한번에 못한다..ㅎㅎ while(조건)을 만족하는 동안! 반복되는 것을 유의하자.
+change >= a가 아니고 change > a 를 썼었는데, 어쨋든 a개수일 때도 교환은 가능하니까.. a개수일 때의 교환을 빼먹어서 값이 자꾸 다르게 나왔었다. 정확한 범위 조건에 대해 주의해야곘다.
✏20231212 화요일
- 명예의전당(Hall Of Fame)의 값을 저장하기 위해 hof 변수를 만들었다. removeFirst( )를 사용해야하기 때문에 mutableListOf<Int>로 선언해줬다.
- 인덱스 0번부터 score의 크기만큼 반복될 수 있도록 for문을 만들었다.
- 명예의전당 k만큼은 그냥 hor에 들어갈 수 있도록 if문을 작성하고, hof의 최소값이 answer의 배열로 들어갈 수 있도록 했다.
- hof의 개수가 k보다 많아지면, 다시 if문을 사용해서 hof의 최소값과 해당 인덱스의 값을 비교했다.
- hof의 최소값보다 크거나 같다면 hof를 오름차순 정렬하여, 제일 작은 첫번째 값을 삭제하고 해당인덱스의 값을 hof에 넣은 후의 최소값을 찾아서 answer에 넣어주었다.
- hof의 최소값보다 작은 경우에도 hof배열의 최소값을 answer에 넣도록 작성해주었다.
class Solution {
fun solution(k: Int, score: IntArray): IntArray {
var answer: IntArray = intArrayOf()
var hof = mutableListOf<Int>()
for(i in 0 until score.size) {
if(i < k) {
hof += score[i]
answer += hof.minOrNull()!!
} else {
if(score[i] >= hof.minOrNull()!!){
hof.sort()
hof.removeFirst()
hof += score[i]
answer += hof.minOrNull()!!
} else {
answer += hof.minOrNull()!!
}
}
}
return answer
}
}
- 원래 hof를 만들때 intArrayOf( )로 선언해줬었는데, public fun <T> MutableList<TypeVariable(T)>.removeFirst() 오류가 났다. 생김새를 보듯이 <제네릭>도 빼먹으면 오류가 난다.
- 위의 이유와 마찬자기로 hof.sort( ).removeFrist( )라고 바로 이어서 작성했더니 오류가 나서 나눠서 작성했다.
- 이전에도 말했지만 min( )이 이젠 사용이 안되고 minOrNull( )이 사용이 되는데, !!를 지양해야하는 건 알지만 null인 경우를 받아들이지 않는 오류가 있어서 !!를 붙여서 간단하게 오류를 피했다.
📖명예의 전당 (1) 문제의 다른 사람 풀이 : PriorityQueue(우선순위 큐)를 사용한 방법
import java.util.*
class Solution {
fun solution(k: Int, score: IntArray): IntArray {
var answer = mutableListOf<Int>()
val pq = PriorityQueue<Int>()
for(item in score) {
if(pq.size < k) {
pq.add(item)
}
else {
if(pq.peek() < item) {
pq.add(item)
pq.poll()
}
}
answer.add(pq.peek())
}
return answer.toIntArray()
}
}
- Priority Queue( ) : 우선순위 큐. 이진트리의 형태로 값을 (오름차순)정렬하여 저장한다.
- for문 안에서도 인덱스 값을 사용할 필요 없이 (값 in 배열) 형태를 사용했다. 더 깔끔해보이는 것 같다.
- Queue에서 사용하는 function
- peek( ) : Queue의 현재상태를 건드리지 않고, head의 값을 반환한다. Queue가 비어있는 경우 null을 반환한다.
- element( ) : peek와 동일한 기능을 하지만, Queue가 비어있어도 null을 반환하지 않는다.
- poll( ) : Queue의 head를 반환하는 동시에 제거한다. 제거된 후 남은 요소들은 한 칸 씩 당겨져 재정렬된다. Queue가 비어있는 경우 null을 반환한다.
- remove( ) : poll과 동일한 기능을 하지만, Queue가 비어있어도 null을 반환하지 않는다.
✏20231213 수요일
- 답을 출력할 요일 배열을 week 이름으로 만들었다. 일주일인 7로 나누어 계산을 할 때, 1월1일이 금요일이므로 첫날. 1일(%7 =1)이 금요일이니까 인덱스 1번이 FRI로 오도록 배열에 입력했다.
- 각 달의 일수를 적은 month 배열을 만들고, day 변수에 주어진 a, b 값에 맞춰 총 일 수를 계산하여 저장한 다음
- day%7을 인덱스로하는 week의 값이 반환되도록 만들었다.
class Solution {
fun solution(a: Int, b: Int): String {
var week = arrayOf("THU","FRI", "SAT", "SUN","MON","TUE","WED" )
var month = arrayOf(31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)
var day = (0 until a-1).map{month[it]}.sum() + b
return week[day % 7]
}
}
- 전체일수를 일주일로 나누어 해당하는 요일을 찾기만 하면 되는 간단한 문제였다.
- 여기에서 범위에 map을 적용하여 계산하는 방법을 사용해 봤다. map 함수는 람다 조건식 안에서 원하는 조건으로 변환된 새로운 컬렉션을 만들어주는 함수이다. 자주 쓰니까 정의도 정확하게 기억하고 다양하게 사용하게 활용하는 방법을 생각해야겠다.
- 최대이익을 반환해야하기 때문에, 큰 점수들 부터 활용될 수 있도록 내림차순 정렬을 해줬다.
- for문 에서 포장해야하는 m개수 만큼 반복될 수 있도록 범위를 주었다. 이때, 한 번 포장한 것들은 재사용될 수 없으므로 step으로 사용한 m개는 건너뛸 수 있도록 해줬다.
- subList를 사용하여 포장할만큼 배열을 끊고, 포장된 packaging배열의 최소점수에 포장개수m을 곱하여 answer에 누적합산 될 수 있도록 했다.
class Solution {
fun solution(k: Int, m: Int, score: IntArray): Int {
var answer: Int = 0
var descendingScore = score.sortedDescending()
for(i in 0 .. score.size-m step m) {
var packaging = descendingScore.subList(i, i+m)
answer += packaging.minOrNull()!! * m
}
return answer
}
}
📖과일 장수 문제의 다른 사람 풀이
class Solution {
fun solution(k: Int, m: Int, score: IntArray): Int {
score.sortDescending()
var answer = 0
for (i in (m - 1)..score.lastIndex step m) {
answer += score[i]
}
return answer * m
}
}
- 내 풀이와 비슷한 풀이인데 훨씬 간결해서 가져와봤다.
- 우선, 내림차순 정렬한 것을 굳이 변수에 집어넣지 않아도 된다는 것을 알게 되었다.
- 그리고 나는 subList를 사용해서 끊어줬는데, 그냥 바로 마지막인덱스 값만 골라서 바로 answer에 더해주는게 충격이었다. 어짜피 정렬해줬으니까 최소값을 쓸 필요가 없었던건데..! 뭔가 반성하게 되는 코드였다.
✏20231214 목요일
- 숫자 3개를 합해야하므로, 3중 반복문을 통해 nums 배열의 숫자를 뽑았다.
- 변수 sum에 뽑은 숫자들의 합을 담고, if문으로 약수가 있는지 판별한다. (있으면1 없으면0)
- 약수가 존재한다면 소수가 아니므로 소수가 0일때, answer에 하나씩 증가하도록 증감연사자를 썼다.
class Solution {
fun solution(nums: IntArray): Int {
var answer = 0
for(i in 0 until nums.size) {
for(j in i+1 until nums.size) {
for(k in j+1 until nums.size) {
var sum = nums[i] + nums[j] + nums[k]
var divisor = 0
for(n in 2 .. sum-1 ) {
if(sum % n == 0) {
divisor = 1
}
}
if(divisor == 0) {
answer++
}
}
}
}
return answer
}
}
- 다른사람의 풀이를 보니까, divisor=1 밑에 break를 넣었다. 생각해보면, 소수인지 아닌지가 중요한 사항이기 때문에, 한번 발견될 때 그냥 break로 빠져나오는게 필요없는 연산도 줄이고 좋은 방법인 것 같다.
=>찾아보니까, 바깥 반복문은 계속 작동하고, 중첩반복문을 빠져나오고 싶을 때 쓰는 방법 중 하나로 flag를 세우는 방법이 있다고 한다. 다른 사람풀이에서는 flag = 1로 되어있는 의문이 풀렸다..
- 다른사람들의 풀이 중 하나로, 아예 소수를 판별하는 펑션을 따로 작성한 후, solution에서 활용하는 방법이 있었는데, 따로 펑션을 세우는 거에도 낯설어하지말고 도전해봐야겠다.
- section의 부분이 다 칠해지면 되는 문제이기 때문에, 앞에서부터 차근차근 칠할 수있도록 반복문의 범위를 section으로 잡았다.
- 한 번 칠했으면 answer이 한번씩 증가할 수 있도록 증감연산자를 사용하고, m의 길이 동안 section에서 포함되는 부분이 있을 수 있기 때문에, 다음에 칠하기 시작할 부분 next를 변수로 선언하여 step m 의 기능을 할 수 있도록 if문을 선언해줬다.
class Solution {
fun solution(n: Int, m: Int, section: IntArray): Int {
var answer: Int = 0
var next = 0
for(i in section){
if(i >= next) {
answer++
next = i + m
}
}
return answer
}
}
- 맨 처음에 솔직히 for(i in section step m)이라고 썼다.. 오류가 나서야 음~ 바보같았다고 깨달았다..ㅎ 어쨋든 section의 다음 값과 칠하기 시작할 시작점을 비교해서 중복으로 칠하지 못하도록 if문을 선언해줬다.
- 겹치는 부분에 대해 어떻게 건너뛰어야 하는지 좀 헤맸었는데, 다른 사람의 풀이 중에 칠하는 범위에 대해 section[0] until section[0] + m 형태로 range를 선언해서, range안에 section 값이 포함된다면 continue로 건너뛰는 방법을 사용한 사람도 있었는데, 어쨋든 원리는 똑같은 거 같고 범위를 설정하는 것도 일이라고 생각해서 가져오지는 않았지만, continue를 활용하는 방법도 있었는데..! 하고 새삼스럽게 깨달아서 적어둔다.
✏20231215 금요일
- sqrt를 활용할 것이기 때문에, kotlin.math.*를 임포트해주었다.
- 약수의 개수를 세야하기 때문에 count 변수와, 개수를 담을 배열 divisor를 만들었다.
- number까지 각 각의 약수의 개수를 구해야하기때문에 for문을 만들고, 그 안에 이중 for문으로 약수의 개수를 구하고, 구한 값을 divisor 배열에 넣은 다음, count 값을 초기화해준다.
- 그렇게 구해진 divisor배열에 map을 통해 limit보다 값이 큰 개수들은 power로 대체하고, 값이 작거나 같으면 그대로의 값을 가지도록 배열을 재정비하고 그 합계를 반환한다.
import kotlin.math.*
class Solution {
fun solution(number: Int, limit: Int, power: Int): Int {
var count = 0
var divisor = arrayOf<Int>()
for(i in 1.. number){
for(j in 1..sqrt(i.toDouble()).toInt()) {
if( j * j == i) count++
else if (i % j == 0 ) count += 2
}
divisor += count
count = 0
}
return divisor.map{i -> if(i>limit) power else i}.sum()
}
}
- 맨 처음에는 그냥 if( i % 2 == 0 )방식을 사용해서 문제를 풀었다. 약수를 구하는 건 꽤 해봤으니까, for문 말고 var divisor = (1..number).map{ }을 사용해서 약수의 개수를 구하고, divisor를 또 새로운 변수에 담아 limit에 따른 조건으로 map을 걸어서 2-3줄 정도로 뚝딱 작성해가지고, 오~ 완전 잘한것같은데 ㅎㅎ 하고 .. 채점을 돌렸더니.. 시간 초과가 나왔다. ㅎㅎ
- 여기까지는 뭐 그래. 내가 너무 map만 썼나? 확장함수보다는 그냥 for를 쓰는게 더 빠르다고 들은 것 같으니까 map으로 작성한 약수 개수 구하는 식을 for문으로 풀고, divisor를 그냥 배열로 선언했으니까, 새롭게 담아줄 필요 없이 바로 divisor.map{i -> if(i>limit) power else i}.sum()을 반환하게 바꿨는데....... 그래도 시간 초과가 나왔다.ㅎ
- 그제서야 약수의 개수를 구하는 다른 방법을 검색해보기 시작했는데, 제곱근을 통해서 구하는게 훨씬 효율적으로 구하는 방법이라고 이미 많은 포스팅들이 있었다.. ㅎㅎ 어쨋든, 숫자 하나가 아니고, 1번부터~number까지 각각의 숫자에 대한 약수의 개수를 구하는거라 for문을 겉에 한번 더 싸야했지만.. 그래서 시간단축이 잘된건지 잘모르겠지만 정상작동하여 통과 받았다.!
📖 제곱근을 통해 약수의 개수를 효율적으로 구하기
import kotlin.math.sqrt
.
.
for(i in 1..sqrt(num.toDouble()).toInt()) {
if( i * i == num) count++
else if (num % i == 0 ) count += 2
}
- n = a*b 일떄, n/b를 하면 a가 나오고, n/a를 하면 b가 나온다. 즉, a가 약수일 때 b가 보장된다는 뜻이다. 이런 경우에는 a인 경우, b인 경우를 전부 계산하면 시간적으로 손해다.
- 따라서, 제곱근을 사용하여 검사 수를 절반으로 줄이고, 다만 제곱근인 경우에는 같은 수를 곱해서 나오는 것이기 때문에 +1을 해주고, 나머지 중 나눠서 딱 떨어지는 숫자가 있을 때 +2를 해주면 된다.
📖 개수 말고 약수 자체를 구하는 방법
import kotlin.math.sqrt
.
.
val result = arrayListOf<Int>()
for (i in 1 .. sqrt(num.toDouble()).toInt()) {
if (num % i == 0) {
result.add(i)
if (num / i != i) result.add(num / i)
}
}
println("${result.sorted()}")