[코테] 기초편 2-1 반복문

Bpius·2023년 4월 7일
0

알고리즘 입문

목록 보기
3/17
post-thumbnail

1. Iteration(이터레이션)

반복문을 통해 객체의 원소 하나하나 접근하는 것을 말한다.
for문에서는 반복문을 사용할 수 있는 객체, 즉 Iterable(반복능한 객체)가 사용된다. for문은 사용자가 지정한 객체의 원소의 수만큼 원소가 변수에 대입되어 반복한다. while문은 조건이 '참'인 동안 while문 아래의 문장이 계속 반복된다.
이러한 특징으로 인해 for문은 매우 직관적으로 사용가능한 장점이 있지만 2, 3중 으로 중첩으로 사용될 시 '모든' 원소를 반복하며 접근하기에 시간이 오래 걸린다는 단점이 있다. while문은 '특정 조건'을 달성할 때까지 반복하는 경우에 더 적합하며, 반드시 while문의 조건을 '거짓'이나 'break'문으로 while문을 멈출 수 있도록 코드에 신경을 써야하는 단점이 있다.
물론 for문 또한 특정 조건을 달성할 때까지 반복하고 반복이 끝나지 않았지만 for문을 빠져나올 수 있는 것이 가능하며, while문도 Iterable한 객체를 사용하여 원소의 요소만큼 반복가능하다.

2. 별찍기 문제 풀기

반복문의 사용을 좀 더 원활히 하기 위해 별찍기 문제로 연습을 하면 실력 향상에 많은 도움이 될 것이다. for/while문을 사용해보자.
추가로 2차원의 별찍기 모양의 전체 크기에서 원하는 곳에만 찍을 수 있도록 체크할 수 있는 배열과 투 포인터(two poitners) 알고리즘을 조금 응용해 보았다.

별찍기 모양은 2차원으로 되어있어 2차원의 빈 리스트 배열을 만든다. 예시에서처럼 별의 모양을 2차원으로 표현한다면 5 × 5 이다.

n = 5 #별찍기 모양 크기에 맞는 값를 변수에 할당한다.
board = [[' '] * n for _ in range(n)] # 빈문자도 문자다
for c in board:
    print(c)
결과:
[' ', ' ', ' ', ' ', ' ']
[' ', ' ', ' ', ' ', ' ']
[' ', ' ', ' ', ' ', ' ']
[' ', ' ', ' ', ' ', ' ']
[' ', ' ', ' ', ' ', ' ']

이렇게 만들어진 5 × 5에 원하는 곳에 별모양을 빈 리스트 안에 넣어 별찍기를 완성한 후, 2중 반복문으로 하나씩 꺼내어 빈문자 아니면 별을 순서대로 출력하면 된다.(반대로 별모양으로 초기화 한 후 빈문자열을 별찍기 모양이 아닌 곳에 빈문자열을 넣거나)
board[i][j]에서 i는 행번호를 j는 열번호를 의미하며, 5 × 5(홀수) 2차원 리스트에서 board[2][2]는 2행 2열(파이썬은 0행 0열부터 시작)은 정중앙이다.
(크기 // 2 = 가운데 인덱스 번호)

투 포인터 알고리즘은 왼쪽과 오른쪽, 아니면 중앙 2개, 왼쪽과 중앙, 중앙과 오른쪽 등의 인덱스의 번호 중 2곳을 포인트로 설정한 후, 이 두 포인터를 움직이며 문제를 풀어갈 수 있게 하는 기법이다. 특히 슬라이딩 윈도우 알고리즘 (Sliding Window)과 같이 사용을 많이 하는데 추후에 자세하게 기술하도록 해보자.
예로 마름모꼴로 별을 찍기 위해서 투 포인터(left=lt, right=rt로 명명했다)를 설정하여 lt/rt를 2로 초기화하여 시작한다. 'for i in range(n)을 사용하여 먼저 변수 i에 0이 할당되면 board[i][lt](0행 2열-첫번째 행 중앙)에 별을 넣는다. 그리고 lt는 1을 빼고 rt는 1을 더하여 위치를 조절하면 lt는 1이 되고 rt는 3으로 조절이 된다.
두번째 for문에서 i에 1이 할당되어 나오면 board[i][lt] ~ board[i][rt](1행 1열 ~ 1행 3열)로, 0행 2열과 같이 보면 마름모꼴로 퍼져 내려오는 모양이 되고, 이 투 포이터 사이를 별로 체운다. 그리고 2행에 최대로 넓어진 후 3행부터는 다시 마름모꼴로 좁혀져야 하기에 lt는 반대로 1씩 더해주고 rt는 빼주면 마름모꼴로 투 포인터가 움직이며 그 투 포이터 사이를 별로 체우는 식이다.

2.1 문제

별찍기의 모양을 위해 크기는 홀수로 지정하였다.

예시) 아래와 같이 별을 찍어보자

*
**
***
****
*****
#for문을 한 번 사용하여 쉽게 찍을 수 있다.
for i in range(1, 6):# 1부터 5까지 i에 순서대로 하나씩 대입된다.
    print(i * '*')
결과:
*
**
***
****
*****
  1. 문제
*****
****
***
**
*
  1. 문제
    *
   **
  ***
 ****
*****
  1. 문제
*****
 ****
  ***
   **
    *
  1. 문제
*
**
***
****
*****
****
***
**
*
  1. 문제
    *
   **
  ***
 ****
*****
 ****
  ***
   **
    *
  1. 문제
*
 *
  *
   *
    *
  1. 문제
    *
   *
  *
 *
*
  1. 문제
*   *
 * *
  *
 * *
*   *
  1. 문제
  *
 ***
*****
 ***
  *
  1. 문제
  *****
   ***
    *
   ***
  *****

2.2 풀이

반복문을 장난감 조립하듯 여러가지 방법으로 계속 코드를 다루고, 생각한 것과는 다른 결과를 보면서 코드를 뜯고 맛봐야 실력이 성장한다.
아래의 풀이가 아닌 자신만의 다른 풀이를 위한 반복문도 사용해보자.

  1. 풀이
for i in range(5, 0, -1):# range 함수 range(10): 10 0부터 9까지 순차적으로 10번 정수 리스트를 생성
    print(i*'*')        #            range(1, 10): 1부터 9까지 순차적으로 9번 정수 리스트를 생성[range(시작번호, 끝번호-1)]
결과:                   #            range(10, 0, -1): 10부터 1까지 순차적으로 10번 정수 리스트 생성[(시작번호,  끝번호-1, 방향)] 
*****                  #                                                                        방향이 -1이면 정수를 역으로 진행
****
***
**
*
  1. 풀이
for i in range(5):
    print((4 - i) * ' ', end='')
    print((i + 1) * '*')
결과:
    *
   **
  ***
 ****
*****
  1. 풀이
for i in range(5, 0, -1):
    print((5 - i) * ' ', end='')
    print(i * '*')
결과:
*****
 ****
  ***
   **
    *
  1. 풀이
for i in range(1, 10):
    if i < 6:
        print(i * '*')
    else:
        print((10 - i) * '*')
결과:
*
**
***
****
*****
****
***
**
*
  1. 풀이
for i in range(9):
    if i < 5:
        print((4 - i) * ' ', end='')
        print((i + 1) * '*')
    else:
        print((i - 4) * ' ', end='')
        print((9 - i) * '*')
결과:
    *
   **
  ***
 ****
*****
 ****
  ***
   **
    *
  1. 풀이
for i in range(5):
    print((i * ' '), end= '')
    print('*')
결과:
*
 *
  *
   *
    *
  1. 풀이
for i in range(5):
    print((4 - i) * ' ', end='')
    print('*')
결과:
    *
   *
  *
 *
*
  1. 풀이
1. for문 사용
for i in range(5):
    if i < 2:
        print((i * 1) * ' ', end='')
        print('*', end='')
        print(((5 - i) - (2 + i)) * ' ', end='')
        print('*')
    elif i == 2:
        print(i * ' ', end='')
        print('*')
    else:
        print((4 - i) * ' ', end='')
        print('*', end='')
        print(((i - 2) + (i - 3)) * ' ', end='')
        print('*')
결과:
*   *
 * *
  *
 * *
*   *
2. for문과 체크배열 사용
board = [[' '] * 5 for _ in range(5)]
for i in range(5):
    for j in range(5):
        if i == j:
            board[i][j] = '*'
        if i + j == 4:
            board[i][j] = '*'
for row in board:
    for j in row:
        print(j, end='')
    print()
결과:
*   *
 * *
  *
 * *
*   *
3. while문과 체크배열 사용
board = [[' '] * 5 for _ in range(5)]
lt = 0
rt = 4
n = 0
while n < 5: # n이 5가 되기 전까지는 '참'으로 계속 반복된다.
    if n < 2:
        board[n][lt] = '*'
        board[n][rt] = '*'
        lt += 1
        rt -= 1
    else:
        board[n][lt] = '*'
        board[n][rt] = '*'
        lt -= 1
        rt += 1
    n += 1 # while문이 무한 루프에 빠지지 않도록 1씩 증가시켜 5가 되면 while문 종료
for row in board:
    for j in row:
        print(j, end='')
    print()
결과:
*   *
 * *
  *
 * *
*   *
  1. 풀이
lt = 2
rt = 2
for i in range(5):
    if i < 2:
        print(lt * ' ', end='')
        print((rt - lt + 1) * '*') # 인덱스 길이 구하기 > rt - lt + 1
        lt -= 1
        rt += 1
    else:
        print(lt * ' ', end='')
        print((rt - lt + 1) * '*')
        lt += 1
        rt -= 1
결과:
  *
 ***
*****
 ***
  *
2. 별찍기의 크기를 변수를 만들어 사용하기
n = 9 #별찍기 크기는 변수 n만 조절하면 된다.
lt = n // 2
rt = n // 2
for i in range(n):
    if i < n // 2:
        print(lt * ' ', end='')
        print((rt - lt + 1) * '*') # 인덱스 길이 구하기 => rt - lt + 1
        lt -= 1
        rt += 1
    else:
        print(lt * ' ', end='')
        print((rt - lt + 1) * '*')
        lt += 1
        rt -= 1
결과:
    *
   ***
  *****
 *******
*********
 *******
  *****
   ***
    *
  1. 풀이
n = 5#별찍기 크기 지정
lt = 0
rt = n - 1
for i in range(n):
    if i < n // 2:
        print(lt * ' ', end='')
        print((rt - lt + 1) * '*') # 인덱스 길이 구하기 => rt - lt + 1
        lt += 1
        rt -= 1
    else:
        print(lt * ' ', end='')
        print((rt - lt + 1) * '*')
        lt -= 1
        rt += 1
결과:
  *****
   ***
    *
   ***
  *****
profile
데이터 굽는 타자기

0개의 댓글