본문 바로가기

[TIL][내일배움캠프]

[내일배움캠프][TIL] 23.11.23 (목) - 기사단원의 무기, 개발자의 마음가짐

1. 코드카타

 

오늘 내가 푼 알고리즘 문제는 '기사단원의 무기'이다.

 

 기사단원의 무기
 
 

 

어후. 이번에는 문제 길이부터 장난이 아니다.

문제를 제대로 이해하는 것부터 시작이었다.

 

내 나름대로 꼼꼼하게 읽어보면서 문제를 정리해봤다.

 

  • 기사단원은 number 명이 있으며, 1번부터 number번까지 순서대로 번호를 부여한다.
  • 기사단원은 자신이 부여받은 번호에 대한 약수의 개수에 해당하는 공격력을 가진 무기를 사야 한다.
  • 단, 그 공격력이 limit보다 클 경우, 그 기사단원은 공격력이 power만큼인 무기를 사야 한다.
  • 이 때, 대장장이가 모든 기사단원의 무기를 만드는 데 필요한 철의 양을 return하는 solution 함수를 완성하기(철의 양은 공격력 1당 1kg.)

이를 토대로, 이번에 내가 풀어야 하는 건 다음과 같다.

 

  • 약수의 개수를 구하는 함수 만들기
  • 이를 토대로 solution 함수 완성하기

 

우선 약수의 개수를 구하는 함수부터 구해보자.

 

약수의 개수를 구하는 방법은 단순하게 생각하면 1부터 number까지의 숫자로 나눠서 나머지가 0이 되는 수를 카운팅하면 된다.

 

그리하여 약수의 개수를 구하는 countDiv() 함수를 완성시켰다.

 

fun countDiv(number: Int): Int {
    var count = 0
        
    for (i in 1..number){
        if (number % i == 0) count++
    }
        
    return count
}

 

이제 이걸 토대로 solution 함수 코드를 작성했다.

 

fun solution(number: Int, limit: Int, power: Int): Int {
    var answer: Int = 0
        
    for (i in 1..number){
        if (countDiv(i) > limit) answer += power
        else answer += countDiv(i)
            
    }
        
    return answer
}

 

만약 countDiv(i)의 값이 limit보다 크면, answer에 power를 더하고, 그렇지 않으면 countDiv(i)를 더한다.

그리고 이를 1번부터 number번까지 반복한다.

 

자. 이제 제출!

 

 

…그리고 예상치 못한 난관에 부딪혔다.

 

채점 결과 통과되지 않았다. 그 이유는 바로….

 

시간 초과.

 

순간 이게 뭐지 싶었지만 곧 그 원인을 알아냈다.

 

약수의 개수를 구하는 식이 굉장히 비효율적이어서.

 

예를 들어서 10을 2로 나누면 몫이 5이고, 나머지가 0이 되니까 10의 약수는 2도 되고, 5도 된다.

하지만, 위의 식은 이런 상황은 무시하고 무조건 1부터 끝까지 계산하니 시간이 굉장히 오래 걸릴 수밖에 없다.

 

그렇기에 나는 저런 상황까지 고려해서 보다 더 효율적인 코드를 짜야하는 상황에 이르렀다.

 

하지만, 아무리 코드를 짜내고 짜봐도 원하는 결과가 나오지 않았다.

그러던 와중, 요즘은 ChatGPT에게 코딩을 물어보는 시대라는 이야기를 얼핏 들었다.

 

그래서 오늘은 ChatGPT의 힘을 한 번 빌려봤다.

뭔가 내 스스로 해결하지 못 했다는 느낌이 들었지만, 어차피 여기서 더 생각을 해봐도 답이 안 나온다.

 

물론 ChatGPT가 주는 코드를 넙죽 받아먹고 끝이 아니고, 왜 이런 식으로 코드를 짰는지 분석할 예정이다. 그래야 다음에 내가 조금이라도 스스로 생각할 수 있으니까.

 

 

ChatGPT에게 약수의 개수를 구하는 방법을 물으니, ChatGPT는 다음과 같은 코드를 보여주었다.

 

fun countDiv(number: Int): Int {
    var count = 1
    var num = number
    var div = 2

    while (div * div <= num) {
        var exp = 0

        while (num % div == 0) {
            exp++
            num /= div
        }

        count *= (exp + 1)
        div++
    }

    if (num > 1) {
        count *= 2 // 마지막으로 남은 소수의 지수에 1을 더한 값
    }

    return count
}

 

…음.

생각했던 것보다 꽤 복잡한데?

 

ChatGPT는 과연 어떤 의도로 이렇게 코드를 짰을까?

하나씩 뜯어보자.

 

    var count = 1
    var num = number
    var div = 2

 

이건 별 거 없다.

num은 number를 받고 계산하기 위함이고, div는 나누는 값이다.

특이한 건 보통 count의 초기값을 0으로 잡는데 얘는 1로 잡았다. 왜지?

 

    while (div * div <= num) {
        var exp = 0

        while (num % div == 0) {
            exp++
            num /= div
        }

        count *= (exp + 1)
        div++
    }

 

이 함수의 핵심 코드다.

 

이 코드의 진행방식은

  • 첫 번째 while문의 조건에 부합하면 우선 exp라는 변수를 선언하고 거기에 초기값 0을 부여한다. 그리고 두 번째 while문에 들어간다.
  • 만약 num의 값이 div로 나뉘어지면 exp에 1을 더하고, num을 div로 나눈 다음 while문을 반복한다.
  • 만약 num의 값이 div로 나누어서 나머지가 생기게 되면 while문을 빠져나오고, 기존 count 값에 반복해서 얻어진 exp 값에 1을 더한 값, 즉 (exp+1)을 곱한 값을 count에 저장한다. 그 다음 div에 1을 더하고 첫 번째 while문을 반복한다.

이걸 찬찬히 뜯어보고 나서야 exp는 지수를 뜻함을 알아챘다.

(그리고 사실 exp가 지수의 약자이다. 너무나도 정직한 ChatGPT의 변수선언)

 

4를 집어넣으면 2로 두 번 나누어지기 때문에 exp에 2가 저장되고, 이는 4가 2의 제곱이라는 것을 정확하게 나타낸다.

 

그리고 while문 안에 exp = 0을 집어넣은 것은 첫 반복문으로 돌아가면 exp 값을 초기화하기 위함이다. while 문 바깥에 집어넣으면 반복되면서 누적되니까.

 

다만, 여기서 제일 이해가 되지 않는 식은 다름 아닌 첫 while문의 조건인 'div*div <= num'이다.

이건 무슨 의도로 저렇게 짰을까?

 

    if (num > 1) {
        count *= 2 // 마지막으로 남은 소수의 지수에 1을 더한 값
    }

    return count
}

 

마지막 if문, 그리고 count를 return하는 종결문이다.

 

이 if문은 마지막으로 남은 소수에 대한 약수의 개수를 계산하기 위해서 집어넣은 부분이다.

 

그리고 여기까지 보고 나서야 ChatGPT가  'div*div <= num'를 쓴 의도를 알아낼 수 있었다.

어차피 2와 3은 반복문을 쓸 필요가 없기 때문에 곧바로 if문으로 가기 위함이고, 나머지 값들 또한 어떻게 보면 소수들로 이루어진 값들이기 때문에 굉장히 빠르게 분류할 수 있다.

 

즉, 굉장히 효율적으로 이 while문을 굴릴 수 있게 되는 것이다.

 

그리고 count의 초기값을 1로 잡은 것도, 여기까지 보고나니 다 계획이 있었다는 걸 알아냈다.

 

모든 경우의 수를 생각하고 만들어낸 굉장히 정교하게 만들어진 식이라는 걸 알게 됐을 때 속으로 감탄했다.

이게… 기술력?

 

 

ChatGPT가 만들어낸 식에 대한 분석을 마치고 다시 채점을 해보니 역시나 이번에는 바로 통과가 되었다. 문제 해결속도를 비교해보니 아까와 확연히 차이가 남을 한 눈에 알 수 있었다.

 

새삼 ChatGPT가 왜 현재 가장 핫한 기술 중 하나인지 되새기게 되는 하루였다.

 


 

2. 개발자의 마음가짐

 

캠프 첫 주차다보니 '어떤 개발자가 되야 하는가?'와 같은, 이른바 동기부여와 관련된 강의들이 많았다.

 

그래서 오늘은 특별히 강사님들이 공통적으로 말하던 '좋은 개발자는 어떤 개발자인가?'를 정리해보기로 했다.

 

이것이 본래의 TIL과는 취지가 맞지 않을 수도 있지만, 그럼에도 추후에 돌이켜봤을 때 상기시키기 위해 정리해보았다.

이것 또한 넓은 의미로는 '배웠다'고 할 수 있으니.

 

좋은 개발자란?

◎ 커뮤니케이션을 원활하게 할 수 있는 개발자.

 가장 중요하다고 모든 강사님들, 멘토분들이 강조하는 덕목이자 내가 생각하는 가장 의외의 덕목.

 내가 생각하기에 좋은 개발자는 코딩을 잘하고, 예상치 못한 오류에 능숙하게 대처할 수 있는 능력을 갖춘 사람이라고 생각했는데 그런 생각과는 정반대였다. 내 상상속에 IT 종사자들은 체크무늬 남방을 입은 너드(Nerd)의 느낌이 강했거든.

 

 그런데 잘 생각해보면 이 커뮤니케이션이 가장 중요한 것이 1인 개발자가 아닌 이상 보통은 팀 프로젝트로 하는 경우가 많은데 거기서 의사소통이 안 되면 협업하는 데에 큰 문제가 생기기 때문.

 

 여기서 말하는 커뮤니케이션이 비단 사람 간의 의사소통 뿐만이 아니라 코드 작성에도 해당이 된다 하셨다. 이를테면 변수 선언을 할 때 어떤 이름을 지을 것인가 고민하는 것도 이러한 의사소통의 일환이라 한다. 팀원 간의 협력에서 타인의 코드를 직관적으로 확인할 수 있는 것도 원활한 의사소통에 도움이 된다고 하셨다.

 

 그리고 지금 이 캠프가 어쩌면 그러한 커뮤니케이션을 배우는 데에 최적화되어 있지 않나 생각된다.

 

 

◎ 배움에 거리낌이 없는 개발자

 IT 산업의 특성상 다른 산업에 비해서 새로운 기술이 더 빨리 나오고, 거기에 뒤처지지 않으려면 그만큼 배우는 자세를 주저하면 안 된다고 하셨다.

 

 또한 모르는 것이 있으면 사소한 것이라도 질문할 자세가 되어있는 것 또한 배움에 거리낌이 없는 자세이다. 

 

 하지만 새로운 것을 배우는 일은 언제나 힘들고 어려운 법. 사람은 언제나 변화보다는 안정을 추구하기 때문에.

 그렇기에 좋은 개발자가 되는 것 또한 힘들고 어렵다.

 

 나는 과연 배움에 거리낌이 없는 사람일까?

 새로운 지식을 습득하기 위해 기존에 쌓아왔던 지식들을 버릴 수 있을까?

 

지금은 어떻게 해야 하는가?

 

물론 이 모든 이야기들이 지금 당장은 와닿지 않았다.

배움은 지금 당장 확 와닿기는 했지만.

 

그렇다면 지금 내가 이 캠프 기간 동안 좋은 개발자가 되기 위해서는 무엇을 어떻게 해야할까?

 

가장 중요한 3가지를 간단히 추려봤다.

 

  • 목적을 달성하기 위해 꾸준히 반복하자.
  • 목적을 달성하기 위한 체계적이고 구체적인 플랜을 만들자.
  • 무엇보다 지금 배운 것들을 꼼꼼하게 기록하고, 정리하자.

이 캠프 기간 동안 이 3가지는 잊지 않고 실천해나갈 것이다.