오늘은 과제에 집중을 하다보니 굵직하게 얻은게 있다기보다는 조금씩 알게 된 사항들이 많았던 것 같다.
일단 오늘 풀었던 알고리즘 문제를 팀원들과 리뷰해보면서 간소화를 정말 많이 할 수 있었다.
class Solution {
fun solution(a: Int, b: Int): Long {
var answer: Long = 0
if (a < b) {
for (i in a..b)) {
answer += i
}
} else if (a == b) {
answer = a.toLong()
} else {
for (i in b..a) {
answer += i
}
} //처음 짠 코드
when {
a < b -> for (i in a..b) {
answer += i
}
a == b -> answer = a.toLong()
a > b -> for (i in b..a) {
answer += i
}
} //when으로 간소화
when {
a < b -> answer = (a..b.toLong()).toList().sum()
a == b -> answer = a.toLong()
a > b -> answer = (b..a.toLong()).toList().sum()
} //자료형 때문에 헤매다가 안쪽으로 toLong()을 넣는 시도 성공
return when {
a < b -> (a..b.toLong()).toList().sum()
a == b -> a.toLong()
a > b -> (b..a.toLong()).toList().sum()
} //answer = when()구문을 시도하다 아예 리턴값으로 뺌
return answer
}
}
class Solution {
fun solution(a: Int, b: Int): Long {
var answer: Long = 0L
for (i in minOf(a, b)..maxOf(a, b)) {
answer += i
}
return answer
}
}
// 최종본. a와 b 중 작은값부터 시작해야하는 문제를 minOf, maxOf로 해결.
초반에는 list를 이용하여 sum()으로 간단하게 만들려는 시도를 하였으나 (a..b).toList()와 같은 응용방식을 몰랐기에 for 구문으로 하나하나 추가하는 방식이 되었기 때문에 식이 꽤나 난잡해졌었다. 그러다보니 그런식으로 할 바에야 아예 answer에 i를 하나하나 더하는 방식이 낫겠다 싶어 나름대로의 간소화를 꾀해본 것이었는데 a가 b보다 큰 경우를 또 고려해야하는 것 때문에 결국 지저분해졌었다.
그래서 일단 코드를 성공시키는데 집중하다보니 제출을 먼저 하고 봤는데, if가 세개를 넘어가면 when을 이용하는것이 나을 거라는 팀원분의 조언에 따라 when으로 고쳐보기도 하고 최초로 생각했던것처럼 list를 이용해서 sum()으로 심플하게 만드는 시도도 해서 다시 피드백을 받게 되었다.
그래서 이야기하던 도중 마지막 방식까지 조언을 얻게 되어 줄일 수 있게 되었다. 그니까 결국 다 팀원 분이 떠먹여줬다.
어쨌거나 느낀것은 (a..b).toList() 같은 방식도 그렇고 사소한 부분에서의 정보나 문법, 용법을 너무 모르고 있다는 사실이었다. 근데 사실 아는것도 이상하다. 5년 전쯤에 c++ 살짝 맛본것 외에는 온통 다 처음 접하는 내용들인데 그런 것들을 어떻게 알고 있겠는가. 그래서 사실 내가 기대했던 수업은 그런 사소한 부분들까지 짚고 넘어가는 것들이었는데 생각보다 독학에 가까워서 기본 뼈대만 제공받고 내가 다 살찌워가는 과정인 것이 막막한 부분이 많았다. 그걸 위해서 팀원들이 있는 것 같아서 새삼 고마움도 많이 느꼈다.
다음 문제는 콜라츠 추측이라는 문제였다.
class Solution {
fun solution(num: Int): Int {
var answer = 0
var collatz = 0
if (num == 1) {
return 0
} else if (num % 2 == 0) {
collatz = num / 2
} else {
collatz = num * 3 + 1
} // 문제의 멍청한 부분
for (i in 1..500) {
if (collatz == 1) {
break
} else if (i == 500) {
return -1
} else if (collatz % 2 == 0) {
collatz = collatz / 2
} else {
collatz = collatz * 3 + 1
}
answer = i + 1
}
return answer
}
}
class Solution {
fun solution(num: Int): Int {
var collatz = num.toLong() // 문제의 부분
for (i in 0..499) {
if (collatz == 1L) {
return i
} else if (collatz % 2 == 0L) {
collatz = collatz / 2
} else {
collatz = collatz * 3 + 1
}
} //1차 축약
for (i in 0..499) {
when {
collatz == 1L -> return i
collatz % 2 == 0L -> collatz /= 2
else -> collatz = collatz * 3 + 1
}
} //최종 축약본
return -1
}
}
이건 최초의 식이 더 심각했다. 지금껀 중간에 고쳐둔걸 가져온것인데 num이 val 값이라고 num=num/2와 같은 연산이 불가능했다. 그것 때문에 굳이 collatz라는 변수를 들고와서 연산을 하려다보니 num을 연산한 값에 대입해야된다는 생각에 for문 안에 있는 식을 그대로 떠와서 for문앞에 배치했다. 지금 생각에야 왜 그런 멍청한 짓을 했을까 싶지만 그때는 collatz와 num을 유기적으로 연결해야된다는 생각에 눈이 멀어 그런 짓을 저지르지 않았나 싶다. 앞서 말했던 그 팀원분의 조언 덕에 var collatz = num.toLong() 과 같은 형태로 collatz에 num을 대입하는 간단한 방법을 사용할 수 있었다. ..진짜 바보같네.
그리고 초반엔 i==500일 때 answer = -1 라는 식을 집어넣었고 for문 아래쪽에 answer = i를 적어두어 500일땐 -1을 리턴하고 collatz==1일 땐 break를 하도록 해서 끝나는 그 i번째를 리턴할 수 있도록 했었다.
답답해서 원래 코드를 가져왔다. 보면 얼마나 멍청한지를 여실히 살펴볼 수 있다. 어쨌거나 연산과정을 한번 바깥으로 뺐던 덕에 i에 +1까지 해준 것을 볼 수 있다.
암튼 첫번째 if에 바로 i를 리턴하도록 했고, 그로 인해 i를 0..499로 고쳤고 collatz에 바로 num.toLong()을 하는 바람에 생긴 형변환 문제를 해결했고 (숫자에 Long타입을 적용할때 0L, 1L과 같은 식으로 적는다는 것도 처음 알았다) for문이 끝나면 자연스럽게 -1을 리턴하도록 하면서 식을 더 간단하게 줄였다.
마지막으로는 또 when으로 고쳤고 collatz /= 2로 줄였다. collatz *= 3 + 1 은 참고로 제대로 연산이 되지 않았다. 3+1 해서 4가 곱해지는 식으로 연산이 되었다. (3+1)처럼 괄호를 하면 에러가 떴다.ㅋㅋ
아무튼 알고리즘만으로 한가득이 돼버렸다. 어제 TIL에 작성한 의문점들을 노션에 정리해놨었는데 그걸 그만 팀원분께 딱 들켜버려서 조금 무안했다. 그래서 그거 관련해서 같이 보며 피드백 시간을 갖게 됐는데 그 덕분에 의문점들이 많이 해결이 됐다. for 조건문 안에 인덱스 값은 이름에 상관없는 값이다. 내 마음대로 할 수 있습니다. 보통은 인덱스값이므로 Int값이지만 list같은 것에 따라 다른 타입이 될 수 있다.
그리고 싱글턴. 문제의 그 녀석을 어느정도 가닥을 잡은 기분이었다.
fun main() {
Bird.fly("참새")
}
class Bird: 새, run {
fun fly(name: String) {
println("${name}가 날아요~")
}
}
여기서 Bird.fly("") 라고 부를 수 있었던 것이 바로 object를 써서 객체를 생성하지 않아도 정보에 접근할 수 있었던 특징 덕분이었던 것이다.
그걸 이용하여 계산기에 있었던 이슈 중에서 when을 반복해서 썼던 것을 해결하게 되었다.
원래는 계산이 끝난 result 값에 다시 연산을 하려면 각 클래스에서 result를 불러오는 과정이 필요했기에 전에 입력했던 연산자를 기반으로 각 클래스에 다시 접근한 후에 그 클래스에서 result값을 불러오는 식으로 진행됐기 때문에 calculte 함수를 실행하기 위해 했던 when과 방식이 거의 같았다.
근데 그걸 companion object를 이용해서 변수를 어느 곳에서 불러도 연동이 되게끔 지정을 하게 되니 그냥 그 값만 불러올 수 있게 되어 한 문장으로 정리가 되는 기가 막힌 상황이 벌어졌다.
class Calculator(private var operator: AbstractOperation) {
companion object {
var lastResultValue = 0.0
}
}
fun main() {
userNum1 = Calculator.lastResultValue
}
class AddOperation(override var num1: Double, operator: String, override var num2: Double) :
AbstractOperation(num1, operator, num2) {
override var result = (num1 + num2).also { Calculator.lastResultValue = it }
}
생략된 부분이 많지만 이런 식으로 하여서 각 연산클래스에 연산을 완료한 result 값을 간단하게 불러올 수 있었다. 생각보다도 유용하고 엄청나게 많이 쓰일 것 같은 기능이라 열심히 실습해보면서 익혀야겠다.
그러게요 생각보다 독학의 느낌이 있네용. 벨로그에 코드
이렇게 하실 때 처음``` 다음에 kotlin(사용언어) 쓰면 더 보기 좋아요!