알고리즘

백준 - 2447번 / map(), join()

joy_lee 2021. 8. 17. 18:28

별 찍기

https://www.acmicpc.net/problem/2447

 

2447번: 별 찍기 - 10

재귀적인 패턴으로 별을 찍어 보자. N이 3의 거듭제곱(3, 9, 27, ...)이라고 할 때, 크기 N의 패턴은 N×N 정사각형 모양이다. 크기 3의 패턴은 가운데에 공백이 있고, 가운데를 제외한 모든 칸에 별이

www.acmicpc.net

문제를 보고 원리도 이해했고, 코딩이 아닌 스스로 문제를 풀려면 가능했다.

그런데 사람이 생각할땐 문제의 3*3 패턴을 기준으로 생각해서 어떻게 해야할지 감이 오지 않았다.

***         ***

* *  옆에  * * 을 어떻게 이어서 출력할 수 있을까 고민했지만 답을 찾지 못했다ㅠ

***         ***

 

결국 고민하다가 인터넷 검색을 통해 찾아봤다.

 

1
2
3
4
5
6
7
8
9
10
11
def concatenate(r1, r2):
    return [''.join(x) for x in zip(r1, r2, r1)]
def star10(n):
    if n == 1:
        return ['*']
    n //= 3
    x = star10(n)
    a = concatenate(x, x)
    b = concatenate(x, [' '*n]*n)
    return a + b + a
print('\n'.join(star10(int(input()))))
cs

(출처 https://conak-diary.tistory.com/20)

 

star10(int(input())) 을 구해서 join으로 이어서 출력한다.

 

일단 concatenate(r1, r2)함수는 인자를 받아 zip 함수에 인자로 넘겨주어 사용한다.

zip 함수는 여러 개의 순회 가능한 객체를 인자로 받고, 각 객체가 담고 있는 원소를 터플의 형태로 차례로 접근할 수 있는 반복자(iterator)를 반환한다. 

1
2
3
4
5
6
7
8
numbers = [123]
letters = ['A''B''C']
for pair in zip(numbers, letters):
    print(pair)
# (1, 'A')
# (2, 'B')
# (3, 'C')
 
cs

 

위 문제의 풀이에서는 아래와 같이 사용된다.

1
2
3
4
5
6
7
r1 = ['***''* *''***']
r2 = ['***''* *''***']
for pair in zip(r1, r2, r1):
    print(pair)
# ('***', '***', '***')
# ('* *', '* *', '* *')
# ('***', '***', '***')
cs

zip을 통해 반환된 객체를 ''.join(x)로 하나로 이어서 출력한다.

(‘***’, ‘***’, ‘***’)

(‘* *’, ‘* *’, ‘* *’)

(‘***’, ‘***’, ‘***’)

는 concatenate()에서 최종적으로

['*********', '* ** ** *', '*********'] 

로 반환된다.

 

star10 함수는 재귀함수이다.

9를 입력할 경우 코드가 다음과 같이 실행된다.

star10()에서는 concatenate()에서 만든 배열들(a, b)을 배열들을 하나로 합쳐서 반환한다.

'\n'.join()을 통해 합친 문자열을 출력하는데, 구분자가 \n이므로 줄을바꿔서 출력한다.

 

다른 방법에서는 1과 0으로 표현해서 나중에 print할 때 1이면 *, 0이면 공백으로 출력하는 과정을 거치는데 이 방법은 처음부터 *과 공백을 사용하므로 그럴 필요가 없다.

 

 

다른 풀이 방법도 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# 별 찍는 재귀 함수
def draw_star(n) :
    global Map
    
    if n == 3 :
        Map[0][:3= Map[2][:3= [1]*3
        Map[1][:3= [101]
        return
 
    a = n//3
    draw_star(n//3)
    for i in range(3) :
        for j in range(3) :
            if i == 1 and j == 1 :
                continue
            for k in range(a) :
                Map[a*i+k][a*j:a*(j+1)] = Map[k][:a] # 핵심 아이디어
 
= int(input())      
 
# 메인 데이터 선언
Map = [[0 for i in range(N)] for i in range(N)]
print(Map)
draw_star(N)
print(Map)
 
for i in Map :
    for j in i :
        if j :
            print('*', end = '')
        else :
            print(' ', end = '')
    print()
cs

(출처 https://study-all-night.tistory.com/5)

 

처음에 Map으로 N*N인 배열을 먼저 만들고, 작은 단위부터 만드는 방법이다.

 

9를 입력한 경우를 표현하면 아래와 같다.

맨 처음 Map을 0으로 초기화해서 생성한다.

재귀함수를 통해 가장 작은 단위인 3*3 이 먼저 만들어진다.

draw_star(3)이 return된 후 draw_star(9)에서 다른 영역을 채워준다.

처음의 3*3 배열을 다른곳에 복사해 붙여넣기 한다고 생각하면 된다.

i == 1 and j == 1인 경우는 continue로 넘어가기 때문에 0으로 남게된다.

 

위의 #핵심 아이디어라고 적힌 부분이 이해하기 힘들었는데, i와 j에 값을 넣어가며 생각해보니 이해할 수 있었다.

 

둘 다 가능하지만 첫 번째 방법이 코드가 더 짧고, 시간도 적게 걸린다.

내장함수 map을 유용하게 사용한 방법이라고 생각한다.

 

참고 사이트

zip 함수 - https://www.daleseo.com/python-zip/

 

[파이썬] 내장 함수 zip 사용법

Engineering Blog by Dale Seo

www.daleseo.com

join 함수 - https://blockdmask.tistory.com/468

 

[python] 파이썬 join 함수 정리 및 예제 (문자열 합치기)

안녕하세요. BlockDMask입니다. 오늘은 파이썬에서 리스트를 문자열로 일정하게 합쳐주는 join 함수에 대해서 알아보려고 합니다. join 함수는 문자열을 다룰 때 유용하게 사용할 수 있는 함수이니

blockdmask.tistory.com

 

'알고리즘' 카테고리의 다른 글

백준 알고리즘(파이썬) - 2798번  (0) 2021.08.23
백준 알고리즘(파이썬) - 11729번  (0) 2021.08.18
백준 - 10870번  (0) 2021.08.13
백준 - 10872번  (0) 2021.08.13
백준 - 1002번  (0) 2021.08.11