Home [lvl2]하노이의 탑
Post
Cancel

[lvl2]하노이의 탑

출처: Programmers > 코딩테스트 연습 > 연습문제 > 하노이의 탑

문제 설명:

하노이 탑(Tower of Hanoi)은 퍼즐의 일종입니다. 세 개의 기둥과 이 기동에 꽂을 수 있는 크기가 다양한 원판들이 있고, 퍼즐을 시작하기 전에는 한 기둥에 원판들이 작은 것이 위에 있도록 순서대로 쌓여 있습니다. 게임의 목적은 다음 두 가지 조건을 만족시키면서, 한 기둥에 꽂힌 원판들을 그 순서 그대로 다른 기둥으로 옮겨서 다시 쌓는 것입니다.

  1. 한 번에 하나의 원판만 옮길 수 있습니다.
  2. 큰 원판이 작은 원판 위에 있어서는 안됩니다.

하노이 탑의 세 개의 기둥을 왼쪽 부터 1번, 2번, 3번이라고 하겠습니다. 1번에는 n개의 원판이 있고 이 n개의 원판을 3번 원판으로 최소 횟수로 옮기려고 합니다.

1번 기둥에 있는 원판의 개수 n이 매개변수로 주어질 때, n개의 원판을 3번 원판으로 최소로 옮기는 방법을 return하는 solution를 완성해주세요.

제한사항

  • n은 15이하의 자연수 입니다.

입출력 예

nresult
2[ [1,2], [1,3], [2,3] ]

입출력 예 설명

입출력 예 #1

다음과 같이 옮길 수 있습니다.

Imgur
Imgur
Imgur
Imgur

코드:

1
2
3
4
5
6
def move(n, start, end, mid):
    if n == 1:
        return [[start, end]]
    return move(n-1, start, mid, end) + move(1, start, end, mid) + move(n-1, mid, end, start)
def solution(n):
    return move(n, 1, 3, 2)

코드 설명:

  • 재귀를 사용하여 각 단계에서 하노이 타워의 원반을 옮기는 과정을 리스트로 반환했다

  • move 함수는 4개의 매개변수(원반의 개수(n), 시작점(start), 종착점(end), 중간점(mid))을 받는다

    • n이 1일 경우, 원반을 바로 start에서 end로 옮긴다
    • n이 1보다 큰 경우, n-1개의 원반을 start에서 mid로 옮긴 다음, 1개의 원반을 start에서 end로 옮기고 마지막으로 n-1개의 원반을 mid에서 end로 옮긴다

우수답변자 코드:

  • 문제가 개편되어 좀 다르지만 yield from을 처음 봤고, 그 활용이 마음에 들어서 가져와 보았다
  • yield from을 활용해 창의적이지만,,,개인적으로는+ 를 쓰는게 더 가독성도 좋고 이해하기 편한듯해 보인다
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 문제가 개편되었습니다. 이로 인해 함수 구성이나 테스트케이스가 변경되어, 과거의 코드는 동작하지 않을 수 있습니다.
# 새로운 함수 구성을 적용하려면 [코드 초기화] 버튼을 누르세요. 단, [코드 초기화] 버튼을 누르면 작성 중인 코드는 사라집니다.
def hanoi(n):

    def _hanoi(m, s, b, d):
        if m == 1:
            yield [s, d]
        else:
            yield from _hanoi(m-1, s, d, b)
            yield [s, d]
            yield from _hanoi(m-1, b, s, d)

    ans = list(_hanoi(n, 1, 2, 3))
    return ans  # 2차원 배열을 반환해 주어야 합니다.

# 아래는 테스트로 출력해 보기 위한 코드입니다.
print(hanoi(2))

yield

yield는 하나의 함수에서 generator을 통해 여러개의 리턴값을 순차적으로 리턴 할 수 있다

yield from

yield from은 뒤에 따라오는 함수로부터 yield를 한다

yield와 yield from의 차이

yieldyield from은 모두 Python의 제너레이터(generator) 기능을 사용하는 키워드이다. 제너레이터는 이터레이터를 생성하는 함수로, 한 번에 하나씩 값(value)을 생성(yield)하고, 메모리에 모든 값을 저장하지 않기 때문에 메모리 효율성이 높다

yieldyield from의 주요 차이점은 다음과 같다:

  • yield: 이 키워드는 제너레이터 함수에서 값을 생성하는 데 사용된다. 함수가 yield를 만나면, 현재 상태를 저장하고 생성한 값을 반환한다. 다음 번 호출 시에는 그 상태를 복원하고, yield 다음의 코드를 실행한다.
1
2
3
4
5
6
7
def simple_generator():     
	yield 1     
	yield 2     
	yield 3  

for i in simple_generator():     
	print(i)  # Prints 1, then 2, then 3
  • yield from: Python 3.3 이후에 추가된 이 키워드는 다른 제너레이터에서 값을 생성하는 데 사용된다. 이를 사용하면, 제너레이터를 다른 제너레이터에 위임(delegate)할 수 있다. 이는 중첩된 제너레이터를 평평하게 만드는 데 유용하다.
1
2
3
4
5
def nested_generator():     
	yield from simple_generator()  # Uses the generator defined above  
	
for i in nested_generator():     
	print(i)  # Prints 1, then 2, then 3

이 예제에서 nested_generatorsimple_generator를 호출하고, 그 값을 직접 생성한다. 이는 간단히 yield from을 사용하여 이루어진다. 이 코드는 simple_generator의 모든 값을 순차적으로 생성한다.

따라서, yield는 값을 직접 생성하고, yield from은 다른 제너레이터에서 값을 생성하는 데 사용된다. 이러한 방식으로, yield from은 제너레이터의 중첩을 처리하는 데 도움이 된다.

우수답변자2 코드:

  • 나와 비슷한 코드지만 초기 설정이 다르다 ```python def hanoi(f, t, m, n): if n == 0: return []

    return hanoi(f, m, t, n-1) + [[f, t]] + hanoi(m, t, f, n-1)

def solution(n): return hanoi(1, 3, 2, n) ```

피드백:

  • 처음엔 답도 없어 보였지만, 메모장에 원판 3개까지 옮기는 방법을 적으니 패턴이 보였고, 4개짜리로 확신이 들었다.
  • 그래도 재귀함수로 구현하는데 꽤 머리아팠는데, 패턴 찾을때와 마찬가지로 3번째까지 일단 코드로 적고보니 점차 답이 보였다.
  • 레벨2치고 굉장히 오래걸렸지만 재귀함수가 생각하기 힘든편이었는데 연습이 되어 좋은것 같다.
This post is licensed under CC BY 4.0 by the author.

[lvl3]네트워크

[SeSAC]프로젝트 소통역량강화