트랙
/
Python
Python
/
연습 문제
/
파스칼의 삼각형
파스칼의 삼각형

파스칼의 삼각형

보통

소개

날씨가 이렇게 좋은데, 교실에서 한 시간을 보내야 한다니 별로 내키지 않아요. 짜증이 난 채로 교실에 들어서는데, 칠판에 묘하게 마음에 드는 삼각형 모양이 눈에 들어와요. 수학 선생님이 오시기를 기다리는 동안, 삼각형에서 몇 가지 규칙성이 눈에 띄지 않을 수 없어요: 바깥쪽 값은 모두 1이고, 각 행은 앞 행보다 값이 하나씩 많으며, 삼각형은 좌우 대칭이에요. 신기하죠!

자리에 앉은 지 얼마 지나지 않아 선생님이 교실에 들어오시고, 이 삼각형이 바로 그 유명한 파스칼의 삼각형이라고 설명해 주세요.

그다음 한 시간 동안, 선생님은 이 삼각형 안에 숨겨진 놀라운 것들을 알려주세요:

  • N개의 값에서 K개의 원소를 고르는 방법이 몇 가지인지 계산하는 데 쓸 수 있어요.
  • 피보나치 수열이 들어 있어요.
  • 홀수와 짝수를 서로 다른 색으로 칠하면, 시에르핀스키 삼각형이라는 아름다운 무늬가 나타나요.

선생님은 다른 쓰임새도 찾아보라고 권하시고, 훨씬 더 많다며 안심시켜 주세요! 바로 그 순간, 학교 종이 울려요. 지난 한 시간 동안 파스칼의 삼각형을 배우는 데 완전히 빠져 있었다는 걸 깨달아요. 가방에서 노트북을 얼른 꺼내 들고 밖으로 나가요. 햇살도, 그리고 파스칼의 삼각형이 간직한 놀라움도 마음껏 즐길 준비가 되었어요.

지침

이번 과제는 파스칼의 삼각형에서 처음 N개 행을 출력하는 거예요.

파스칼의 삼각형은 양의 정수로 이루어진 삼각형 모양의 배열이에요.

파스칼의 삼각형에서는 한 행에 있는 값의 개수가 그 행의 번호와 같아요(행 번호는 1부터 시작해요). 따라서 첫 번째 행에는 값이 하나, 두 번째 행에는 값이 둘, 이런 식으로 늘어나요.

맨 위의 첫 번째 행에는 값이 하나뿐이에요: 1. 그다음 행의 값들은 이전 행에서 현재 위치의 바로 오른쪽과 바로 왼쪽에 있는 수를 더해서 구해요.

이전 행의 현재 위치 왼쪽이나 오른쪽에 값이 없다면(가장 왼쪽과 가장 오른쪽 위치에서만 이렇게 돼요), 그 위치의 값은 0으로 생각하고 더해요(덧셈에서 사실상 "무시"하는 셈이죠).

예시

파스칼의 삼각형에서 처음 5개 행을 살펴볼까요:

    1
   1 1
  1 2 1
 1 3 3 1
1 4 6 4 1

맨 위 행에는 값이 하나 있고, 그 값은 1이에요.

가장 왼쪽과 가장 오른쪽 값은 앞 행에서 고려할 위치가 하나뿐이에요. 왼쪽 값은 자기 오른쪽 위치를, 오른쪽 값은 자기 왼쪽 위치를 보죠. 맨 위 값이 1이므로, 가장 왼쪽과 가장 오른쪽 값도 모두 1이라는 걸 알 수 있어요.

나머지 값들은 모두 고려할 위치가 두 개예요. 예를 들어 다섯 번째 행(1 4 6 4 1)의 가운데 값은 6이에요. 앞 행에서 그 왼쪽과 오른쪽에 있는 값이 각각 3과 3이기 때문이죠:

Python에서 이 연습 문제를 구현하는 방법: 재귀

이 연습 문제는 루프 대신 recursion을 사용해 완성하도록 설계되었어요. 재귀 함수는 자기 자신을 호출하는 함수로, 자기 자신을 기준으로 정의되는 문제를 풀 때 유용해요. 무한 재귀를 피하기 위해(더 정확히는 스택 오버플로를 피하기 위해) "기본 사례"라고 하는 것을 사용해요. 기본 사례에 도달하면 재귀적이지 않은 값이 반환되고, 그러면 이전 함수 호출이 값을 계산해 반환할 수 있게 돼요. 이런 식으로 스택을 따라 거슬러 내려가면서 첫 번째 함수 호출이 답을 반환할 때까지 이어져요. 5! (즉 5 * 4 * 3 * 2 * 1)의 답을 구하는 재귀 함수를 이렇게 작성할 수 있어요:

def factorial(number):
  if number <= 1:  # base case
    return 1

  return number * factorial(number - 1) # recursive case

print(factorial(5)) # returns 120

마지막으로, Python은 재귀 호출을 할 수 있는 횟수를 제한하고(기본값 1000회) 꼬리 재귀를 최적화하지 않는다는 점을 알아 두세요.

예외 메시지

때로는 예외를 발생시키는 것이 필요해요. 이렇게 할 때는 오류의 원인이 무엇인지 알려 주는 의미 있는 오류 메시지를 항상 포함해야 해요. 그러면 코드를 더 읽기 쉽게 만들고 디버깅에 크게 도움이 돼요. 오류 원인이 특정 유형일 것이라고 알고 있는 상황이라면 내장 오류 유형 중 하나를 발생시켜도 되지만, 그래도 의미 있는 메시지를 포함해야 해요.

이 연습 문제에서는 rows() 함수에 음수가 전달되면 raise 문을 사용해 여러 개의 ValueError를 "던져야" 해요. 테스트를 통과하려면 exception을 raise하고 메시지도 함께 포함해야 해요.

메시지와 함께 ValueErrors를 발생시키려면 메시지를 exception 유형에 인자로 작성해요:

# if the rows function is passed a negative number.
raise ValueError("number of rows is negative")
GitHub에서 편집 링크가 새 창이나 탭에서 열려요
Python Exercism

파스칼의 삼각형 문제를 시작해 볼 준비가 됐나요?

Exercism에 가입하고 Python 트랙을 개념 17개연습 문제 146개, 그리고 실제 사람의 멘토링과 함께 배우고 익혀 보세요. 모두 무료예요.