상세 컨텐츠

본문 제목

[프로젝트 오일러] 1000보다 작은 자연수 중에서 3 또는 5의 배수를 모두 더하면?

IT/프로그래밍

by James Lee. 2015. 12. 16. 21:57

본문

첫 프로젝트 오일러 포스팅입니다.

(사실 4번까지 풀었지만 올리기 귀찮음으로 인하여 미루다가 이제서야 올립니다..)

문제는 아래와 같습니다.

10보다 작은 자연수 중에서 3 또는 5의 배수는 3, 5, 6, 9 이고, 이것을 모두 더하면 23입니다.

1000보다 작은 자연수 중에서 3 또는 5의 배수를 모두 더하면 얼마일까요?

※ 이 문제에서 1000보다 작은 자연수라는 조건에는 1000도 포함입니다.


코드를 작성함에 있어서 가장 기본적인 원칙은 아래와 같습니다.

  1. clean code를 최대한 준수하도록 합니다.
    • 코드의 라인 수가 짧을 수록 좋겠지만 그것보다는 가독성에 더 초점을 두었습니다.
    • 최대한 모듈별로 나누어서 다른 사람들도 코드를 이해 할 수 있도록 하였습니다.
  2. 1의 가독성이 유지되는 선에서 가능한한 코드를 짧게 합니다.
  3. 언어는 Java를 사용합니다.
  4. 테스트 주도 개발 기법(TDD, Test - Driven - Development)을 이용합니다.
  5. 가능한한 혼자 힘으로 해결합니다.
    • 막히는 부분이 있을때, 비효율적인 코드가 나올지라도 혼자 힘으로 해결합니다.
    • 이는 저의 사고력을 키우기 위한 프로젝트이기도 하기 때문입니다.
테스트 주도 개발 기법에 대한 포스팅은 제가 1년 전에 작성한 http://jhleed.tistory.com/13 을 참조하세요 :)

완성된 코드는 아래와 같습니다.

public class MultipleOf3And5 {
public int getSumOf(int inputNumber) {
int result = 0;
for(int number=1;number<=inputNumber;number++){
if(number%3 == 0 || number %5 == 0){
result += number;
}
}
return result;
}
}
아 ~ 별거 아니네?! 라고 느껴지신다면 감사합니다.
(뭐야 이코드 복잡하다! 라고 느껴지신다면 아직 제가 깔끔하게 짜는 스킬이 부족한 탓이겠지요. ㅠㅠ)


풀이과정은 아래와 같습니다.

TDD 규칙 1. TDD는 테스트를 먼저 만드는 것으로부터 시작합니다. (Test First)

가장 간단한 정답을 하드코딩으로 통과시킨다. (1 이하의 수에서 3과 5의 배수의 합은 0.)


해당 테스트를 하드코딩으로 통과시킵니다.



Step 2. 그 다음으로 간단한 테스트는 무엇일까? 3으로 해봅니다.



3 또한 하드코딩으로 통과시킵니다.



여기서부터는 테스트 작성 단계는 생략하고 문제 풀이 과정만 올리겠습니다.



5 이하의 자연수에서 3과 5의 배수의 합은 3 + 5 = 8입니다.

역시나 우선 하드코딩!



자, 이제 리팩토링을 할 단계입니다. 

하드코딩 된 결과값 사이에서 규칙을 찾아내고, 중복을 제거하고, 일반화를 하는 과정이죠.

8은 사실 3과 5를 더한 결과값입니다.


return 값을 result라는 그릇에 담도록 하죠.



아래와 같은 형태로 바꿔보았습니다.

형태를 계속 바꿔주는 것은 최대한 중복되는 형태로 만들어서 일반화시키기 위함입니다.

무슨 말인지 잘 이해가 안가시는 분도 다다음 단계까지 따라오세요 :)



이제부터 일반화의 시작점입니다.

이전 단계에는 드러나지 않았지만 사실 아래와 같은 원리가 숨겨져 있습니다. (눈에 보이지 않는 규칙을 찾아내기)



다른 곳에도 이렇듯 보이지 않는 규칙이 적용되지요.

이쯤에서 프로그래밍을 해보신 분들은 뭔가 보이지 않나요~?



아래와 같이 반복문을 써서 코드의 양을 줄이고 일반화시킬 수 있습니다. (하드코딩의 일반화)



이 코드는 아래와 같이 조금 더 깔끔하게 쓸 수 있겠군요 (리팩토링)



i라는 의미없는 이름보다는 number로 바꾸어 보았습니다. (리팩토링)

자, 이렇게 5라는 입력값이 들어왔을때 일반화된 솔루션을 도출해 낼 수 있게 되었습니다.

그렇다면 하드코딩되어 있는 4와 3에도 이 솔루션을 적용해 볼 수 있을까요?


아래와 같이 4와 5에도 동일한 솔루션을 이용하여 문제를 해결할 수 있습니다. 

(테스트 코드가 존재하기 때문에 이것을 바로 알 수 있습니다.)



3, 4, 5 모든 if문에서 동일한 방법을 이용하여 문제를 해결하고 있습니다.

이것을 하나로 묶어주면 아래와 같이 진정으로 일반화된 솔루션 (Generalized Solution)이 완성되었습니다.



그럼 이 솔루션이 1000 이하의 3과 5의 배수의 합을 구하는 문제를 풀 수 있을까요?


음..오랜만에 글을 써서 마무리 짓는것이 상당히 어색하네요.

TDD에 관하여 너무 짧게 설명한 것 같아서 약간만 보충을 하겠습니다.

TDD는 아래와 같은 3 Steps로 이루어집니다.

1. 실패하는 테스트 코드를 먼저 작성한다. (가장 단순한 케이스로)

2. 하드코딩을 이용하여 가장 간단하게 통과시킨다.

3. 리팩토링을 한다.

의심의 여지 없이 TDD에서는 3. 리팩토링이 핵심이라고 생각하는데 글로 짧게 설명하기는 꽤 어렵습니다. 

(위의 간단한 3단계 Step에 대해서만도 십수권의 책이 나올 정도니까요.)

TDD를 하다 보면 자주 나오는 패턴은 눈에 보이지 않는 규칙들을 발견하고, 중복을 인위적으로 생성한 다음 리팩토링을 한다는 것 정도입니다.

저도 계속 배우고 적용하는 단계이니 뭔가 깨닫는 것이 있다면 포스팅에 함께 올리도록 할게요.

이 문제는 사실 쉬운 편에 속해서 굳이 TDD와 같은 개발 기법을 사용할 필요가 없을 수도 있지만 

쉬운 문제부터 TDD를 적용해서 풀어본다면 나중에 어려운 문제가 나오더라도 TDD를 적용하여 익숙하게 풀 수 있을 거에요.

이상으로 첫 프로젝트 오일러 문제 풀이 포스팅을 마치도록 하겠습니다 :)

관련글 더보기

댓글 영역