Code/Algorithm

[Algorithm] 기본 자료구조와 배열_2

heedy 2022. 11. 25. 14:29
728x90

이전 글과 이어지기 때문에 이전 글을 먼저 보시는 것이 좋습니다.

2022.11.21 - [Code/Algorithm] - [Algorithm] 기본 자료구조와 배열

 

[Algorithm] 기본 자료구조와 배열_1

02 - 1 자료구조와 배열 실습 2-1 학생 5명의 시험 점수를 입력받아 합계와 평균을 출력하기 # 학생 5명의 시험 점수를 입력받아 합계와 평균을 출력하기 print('학생 그룹 점수의 합계와 평균을 구합

heejins.tistory.com


02 - 1 배열이란?

배열 원소의 최댓값 구하기

# a의 원소가 3개일 때

maximum = a[0]
if a[1] > maximum: maximum = a[1]
if a[2] > maximum: maximum = a[2]
# a의 원소가 4개일 때

maximum = a[0]
if a[1] > maximum: maximum = a[1]
if a[2] > maximum: maximum = a[2]
if a[3] > maximum: maximum = a[3]

배열 원소의 최댓값을 구하는 순서도

함수로 정의

# 배열 원소의 최대값 구하기

def max_of(a):
  maximum = a[0]
  for i in range(1, len(a)):
    if a[i] > maximum:
      maximum = a[i]

배열 원소의 최댓값을 구하는 함수 구현하기

실습 2-2 시퀀스 원소의 최댓값 출력하기

# 시퀀스 원소의 최대값 출력하기

from typing import Any, Sequence

def max_of(a: Sequence) -> Any:
  """시퀀스형 a 원소의 최댓값을 반환"""
  maximum = a[0]
  for i in range(1, len(a)):
    if a[i] > maximum:
      maximum = a[i]
  return maximum

if __name__ == '__main__':
  print('배열의 최댓값을 구합니다.')
  num = int(input('원소 수를 입력세요.: '))
  x = [None] * num

  for i in range(num):
    x[i] = int(input(f'x[{i}]값을 입력하세요.: '))

  print(f'최대값은 {max_of(x)}입니다.')
배열의 최댓값을 구합니다.
원소 수를 입력세요.: 5
x[0]값을 입력하세요.: 123
x[1]값을 입력하세요.: 29
x[2]값을 입력하세요.: 12340
x[3]값을 입력하세요.: 2
x[4]값을 입력하세요.: 93
최대값은 12340입니다.

주석과 자료형 힌트

  • Any: 제약이 없는 임의의 자료형
  • Sequence: 시퀀스형(sequence type)을 의미
    → 시퀀스형에는 리스트(list)형, 바이트 배열(bytearry)형, 문자열(str)형, 튜플(tuple)형, 바이트열(bytes)형이 있습니다.

재사용할 수 있는 모듈 작성하기

  • 모듈: 하나의 스크립트 프로그램, 학장자(.py)를 포함하지 않는 파일의 이름 자체를 모듈 이름으로 사용합니다.
  • 스크립트 프로그램이 직접 실행될 때 변수__name__은 '__main__'입니다.
  • 스크립트 프로그램이 임포트될 때 변수 __name__은 원래의 모듈 이름입니다.

모듈 테스트하기

입력받을 때 원소 수를 결정하기

실습 2-3 배열 원소의 최댓값을 구해서 출력하기(원솟값을 입력받음)

# 배열 원소의 최댓값을 구해서 출력하기(원솟값을 입력받음)

from max import max_of

print('배열의 최댓값을 구합니다.')
print('주의: "End"를 입력하면 종료합니다.')

number = 0
x = []

while True:
  s = input(f'x[{number}]값을 입력하세요.: ')
  if s == 'End':
    break
  x.append(int(s))
  number += 1

print(f'{number}개를 입력했습니다.')
print(f'최댓값은 {max_of(x)}입니다.')
배열의 최댓값을 구합니다.
주의: "End"를 입력하면 종료합니다.
x[0]값을 입력하세요.: 15
x[1]값을 입력하세요.: 72
x[2]값을 입력하세요.: 64
x[3]값을 입력하세요.: 7
x[4]값을 입력하세요.: End
4개를 입력했습니다.
최댓값은 72입니다.

배열의 원솟값을 난수로 결정하기

실습 2-4 배열 원소의 최댓값을 구해서 출력하기(원솟값을 난수로 생성)

# 배열 원소의 최댓값을 구해서 출력하기(원솟값을 난수로 생성)

import random
from max import max_of

print('난수의 최댓값을 구합니다.')
num = int(input('난수의 개수를 입력하세요.: '))
lo  = int(input('난수의 최솟값을 입력하세요.: '))
hi = int(input('난수의 최댓값을 입력하세요.: '))
x = [None] * num # 원소 수가 num인 리스트를 생성

for i in range(num):
  x[i] = random.randint(lo, hi)

print(f'{(x)}')
print(f'이 가운데 최댓값은 {max_of(x)}입니다.')
난수의 최댓값을 구합니다.
난수의 개수를 입력하세요.: 3
난수의 최솟값을 입력하세요.: 6
난수의 최댓값을 입력하세요.: 87
[61, 51, 76]
이 가운데 최댓값은 76입니다.

튜플, 문자열, 문자열 리스트의 최댓값 구하기

실습 2-5 각 배열 원소의 최댓값을 구해서 출력하기(투플, 문자열, 문자열 리스트)

# 각 배열 원소의 최댓값을 구해서 출력하기(튜플, 문자열, 문자열 리스트)

from max import max_of

t = (4, 7, 5.6, 2, 3.14, 1)
s = 'string'
a = ['DTS','AAC','FLAC']

print(f'{t}의 최댓값은 {max_of(t)}입니다.')
print(f'{s}의 최댓값은 {max_of(s)}입니다.')
print(f'{a}의 최댓값은 {max_of(a)}입니다.')
(4, 7, 5.6, 2, 3.14, 1)의 최댓값은 7입니다.
string의 최댓값은 t입니다.
['DTS', 'AAC', 'FLAC']의 최댓값은 FLAC입니다.

리스트와 튜플 2

따로따로 생성한 리스트, 튜플의 동일성 판단하기

# 따로따로 생성한 리스트, 튜플의 동일성 판단하기

lst1 = [1,2,3,4,5]
lst2 = [1,2,3,4,5]
print(lst1 is lst2)

>>> False

리스트, 튜플의 대입

# 리스트, 튜플의 대입

llst1 = [1,2,3,4,5]
lst2 = lst1
print(lst1 is lst2)

>>> True

lst1[2] = 9
print(lst1)

>>> [1, 2, 9, 4, 5]

print(lst2)

>>> [1, 2, 9, 4, 5]

리스트 스캔

실습 2C-1 리스트의 모든 원소를 스캔하기(원소 수를 미리 파악)

# 리스트의 모든 원소를 스캔하기(원소 수를 미리 파악)

x = ['John','George','Paul','Ringo']

for i in range(len(x)):
  print(f'x[{i}] = {x[i]}')
x[0] = John
x[1] = George
x[2] = Paul
x[3] = Ringo

실습 2C-2 리스트의 모든 원소를 enumerate() 함수로 스캔하기

# 리스트의 모든 원소를 enumerate() 함수로 스캔하기

x = ['John','George','Paul','Ringo']

for i, name in enumerate(x):
  print(f'x[{i}] = {name}')
x[0] = John
x[1] = George
x[2] = Paul
x[3] = Ringo

실습 2C-3 리스트의 모든 원소를 enumerate() 함수로 스캔하기(1부터 카운트)

# 리스트의 모든 원소를 enumerate() 함수로 스캔하기(1부터 카운트)

x = ['John','George','Paul','Ringo']

for i, name in enumerate(x, 1):
  print(f'{i}번째 = {name}')
1번째 = John
2번째 = George
3번째 = Paul
4번째 = Ringo

실습 2C-4 리스트의 모든 원소를 스캔하기(인덱스 값을 사용하지 않음)

# 리스트의 모든 원소를 스캔하기(인덱스값을 사용하지 않음.)

x = ['John','George','Paul','Ringo']

for i in x:
  print(i)
John
George
Paul
Ringo

배열 원소를 역순으로 정렬하기

배열 원소를 역순으로 정렬하는 알고리즘을 간단히 나타내면 다음과 같습니다

for i in range(n // 2):
	a[i]와 a[n - i - 1]의 값을 교환

실습 2-6 뮤터블 시퀀스 원소를 역순으로 정렬

# 뮤터블 시퀀스 원소를 역순으로 정렬 py 파일

from typing import Any, MutableSequence

def reverse_array(a: MutableSequence) -> None:
  """뮤터블 시퀀스 a의 원소를 역순으로 정렬"""
  n = len(a)
  for i in range(n // 2):
    a[i], a[n - i -1] = a[n- i -1], a[i]

if __name__ == '__main__':
  print('배열 원소를 역순으로 정렬합니다.')
  nx = int(input('원소 수를 입력하세요.: '))
  x = [None] * nx

  for i in range(nx):
    x[i] = int(input(f'x[{i}]값을 입력하세요.: '))

  reverse_array(x) # x를 역순으로 정렬

  print('배열 원소를 역순으로 정렬했습니다.')
  for i in range(nx):
    print(f'x[{i}] = {x[i]}')

리스트를 역순으로 정렬하기

# 리스트를 역순으로 정렬

x.reverse()

# 역순으로 정렬한 리스트 생성
y = list(reversed(x))

기수 변환하기(n진수 구하기)

  • 기수: 수를 나타내는 데 기초가 되면 10진법에서는 0~9까지 정수를 말합니다. 
    ex) 1, 2, 3 ···
  • 서수: 사물의 순서를 나타냅니다. 
    ex) 첫번째, 두번째, 세번째 ···

기수 살펴보기

  • 10진수
    • 1자릿수: 0~9까지의 수를 나타냅니다.
    • 2자릿수: 10~99까지의 수를 나타냅니다.
    • 3자릿수: 100~999까지의 수를 나타냅니다.
  • 8진수
    • 1자릿수: 0~7까지의 수를 나타냅니다.
    • 2자릿수: 10~77까지의 수를 나타냅니다.
    • 3자릿수: 100~777까지의 수를 나타냅니다.
  • 16진수
    • 0 1 2 3 4 5 6 7 8 9 A B C D E F(16종류)

실습 2-7 10진수 정숫값을 입력받아 2~36진수로 변환하여 출력하기

# 10진수 정숫값을 입력받아 2~36진수로 변환하여 출력하기

def card_conv(x: int, r: int) -> str:
  """정숫값 x를 r진수로 변환한 뒤 그 수를 나타내는 문자열을 반환"""


  d = '' # 변환후의 문자열
  dchar = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'

  while x > 0:
    d += dchar[x % r] # 해당하는 문자를 꺼내 결합
    x //= r

  return d[::-1] # 역순으로 반환


if __name__ == '__main__':
  print('10진수를 n진수로 변환합니다.')

  while True:
    while True: # 음이 아닌 정수를 입력받음.
      no = int(input('변환할 값으로 음이 아닌 정수를 입력하세요.: '))
      if no > 0:
        break

    while True: # 2~36 진수의 정숫값을 입력받음
      cd = int(input('어떤 진수로 변환할까요?: '))
      if 2 <= cd <= 36:
        break
    
    print(f'{cd}진수로는 {card_conv(no, cd)}입니다.')

    retry = input('한 번 더 변환할까요?(Y···예 / N···아니요): ')
    if retry in {'N','n'}:
      break

수정

# 10진수 정숫값을 입력받아 2~36진수로 변환하여 출력하기(수정)

def card_conv(x: int, r: int) -> str:
  """정숫값 x를 r진수로 변환한 뒤 그 수를 나타내는 문자열을 반환"""


  d = '' # 변환후의 문자열
  dchar = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
  n = len(str(x)) # 변환하기 전의 자릿수

  print(f'{r:2} | {x:{n}d}')
  while x > 0:
    print(' +' + (n+2) * '-')
    if x // r:
      print(f'{r:2} | {x //r:{n}d} ···{x % r}')
    else:
      print(f'  {x //r:{n}d} ···{x % r}')
    d += dchar[x % r] # 해당하는 문자를 꺼내 결합
    x //= r

  return d[::-1] # 역순으로 반환


if __name__ == '__main__':
  print('10진수를 n진수로 변환합니다.')

  while True:
    while True: # 음이 아닌 정수를 입력받음.
      no = int(input('변환할 값으로 음이 아닌 정수를 입력하세요.: '))
      if no > 0:
        break

    while True: # 2~36 진수의 정숫값을 입력받음
      cd = int(input('어떤 진수로 변환할까요?: '))
      if 2 <= cd <= 36:
        break
    
    print(f'{cd}진수로는 {card_conv(no, cd)}입니다.')

    retry = input('한 번 더 변환할까요?(Y···예 / N···아니요): ')
    if retry in {'N','n'}:
      break

함수 사이에 인수 주고받기

실습 2C-5 1부터 n까지 정수의 합 구하기

# 1부터 n까지 정수의 합 구하기

def sum_1ton(n):
  """1부터 n까지 정수의 합"""

  s = 0
  while n > 0:
    s += n
    n -= 1
  return s

x = int(input('x의 값을 입력하세요.: '))
print(f'1부터 {x}까지 정수의 합은 {sum_1ton(x)}입니다.')

실습 2C-6 리스트에서 임의의 원솟값을 업데이트하기

# 리스트에서 임의의 원솟값을 업데이트 하기

def change(lst, idx, val):
  """lst[idx]의 값을 val로 없데이트"""
  lst[idx] = val

x = [11,22,33,44,55]
print('x = ', x)

index = int(input('업데이트할 인덱스를 서택하세요.: '))
value = int(input('새로운 값을 입력하세요.: '))

change(x, index, value)
print(f'x = {x}')
x =  [11, 22, 33, 44, 55]
업데이트할 인덱스를 서택하세요.: 2
새로운 값을 입력하세요.: 99
x = [11, 22, 99, 44, 55]

소수 나열하기

  • 소수: 2부터 n - 1까지 어떤 정수로도 나누어 떨어지지 않는 수
  • 합성수: 2부터 n - 1까지 나누어 떨어지는 정수가 하나 이상 존재하는 수

실습 2-8 1,000 이하의 소수를 나열하기

# 1,000 이하의 소수를 나열하기

counter = 0 # 나눗셈 횟수를 카운트

for n in range(2, 1001):
  for i in range(2, n):
    counter += 1
    if n % i == 0: # 나누어 떨어지면 소수가 아님
      break # 반복은 더 이상 불필요하여 중단
  else: # 끝까지 나누어 떨어지지 않으면 다음을 수행
    print(n)

print(f'나눗셈을 실행한 횟수: {counter}')

>>> 결과

더보기

2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 101 103 107 109 113 127 131 137 139 149 151 157 163 167 173 179 181 191 193 197 199 211 223 227 229 233 239 241 251 257 263 269 271 277 281 283 293 307 311 313 317 331 337 347 349 353 359 367 373 379 383 389 397 401 409 419 421 431 433 439 443 449 457 461 463 467 479 487 491 499 503 509 521 523 541 547 557 563 569 571 577 587 593 599 601 607 613 617 619 631 641 643 647 653 659 661 673 677 683 691 701 709 719 727 733 739 743 751 757 761 769 773 787 797 809 811 821 823 827 829 839 853 857 859 863 877 881 883 887 907 911 919 929 937 941 947 953 967 971 977 983 991 997

나눗셈을 실행한 횟수: 78022

알고리즘 개선

# 1,000 이하의 소수를 낭려하기(알고리즘 개선 1)

counter = 0                           # 나눗셈 횟수를 카운트
ptr = 0                               # 이미 찾은 소수의 개수
prime = [None] * 500                  # 소수를 저장하는 배열

prime[ptr] = 2                        # 2는 소수이므로 초깃값으로 지정
ptr += 1

for n in range(3, 1001, 2):           # 홀수만을 대상으로 설정
  for i in range(1, ptr):             # 이미 찾은 소수로 나눔
    counter += 1
    if n % prime[i] == 0:             # 나누어 떨어지면 소수가 아님
      break                           # 반복 중단
  else:                               # 끝까지 나누어 떨어지지 않았다면
    prime[ptr] = n                    # 소수로 배열에 등록
    ptr += 1

for i in range(ptr):                  # ptr의 소수를 출력
  print(prime[i])
print(f'나눗셈을 실행한 횟수: {counter}')

>>> 결과

더보기

2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 101 103 107 109 113 127 131 137 139 149 151 157 163 167 173 179 181 191 193 197 199 211 223 227 229 233 239 241 251 257 263 269 271 277 281 283 293 307 311 313 317 331 337 347 349 353 359 367 373 379 383 389 397 401 409 419 421 431 433 439 443 449 457 461 463 467 479 487 491 499 503 509 521 523 541 547 557 563 569 571 577 587 593 599 601 607 613 617 619 631 641 643 647 653 659 661 673 677 683 691 701 709 719 727 733 739 743 751 757 761 769 773 787 797 809 811 821 823 827 829 839 853 857 859 863 877 881 883 887 907 911 919 929 937 941 947 953 967 971 977 983 991 997

나눗셈을 실행한 횟수: 14622

알고리즘 개선 2

# 1,000 이하의 소수를 나열하기(알고리즘 개선 2)

counter = 0                           # 곱셈과 나눗셈을 합한 횟수
ptr = 0                               # 이미 찾은 소수의 개수
prime = [None] * 500                  # 소수를 저장하는 배열

prime[ptr] = 2                        # 2는 소수
ptr += 1

prime[ptr] = 3                        # 3은 소수
ptr += 1

for n in range(5, 1001, 2):           # 홀수만을 대상으로 설정
  i = 1
  while prime[i] * prime[i] <= n:
    counter += 2
    if n % prime[i] ==0:              # 나누어 떨어지므로 소수가 아님
      break                           # 반복 중단
    i += 1
  else:                               # 끝까지 나누어 떨어지지 않았다면
    prime[ptr] = n                    # 소수로 배열에 등록
    ptr += 1
    counter += 1

for i in range(ptr):                  # ptr의 소수를 출력
  print(prime[i])
print(f'곱셈과 나눗셈을 실행한 횟수: {counter}')

>>> 결과

더보기

2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 101 103 107 109 113 127 131 137 139 149 151 157 163 167 173 179 181 191 193 197 199 211 223 227 229 233 239 241 251 257 263 269 271 277 281 283 293 307 311 313 317 331 337 347 349 353 359 367 373 379 383 389 397 401 409 419 421 431 433 439 443 449 457 461 463 467 479 487 491 499 503 509 521 523 541 547 557 563 569 571 577 587 593 599 601 607 613 617 619 631 641 643 647 653 659 661 673 677 683 691 701 709 719 727 733 739 743 751 757 761 769 773 787 797 809 811 821 823 827 829 839 853 857 859 863 877 881 883 887 907 911 919 929 937 941 947 953 967 971 977 983 991 997

곱셈과 나눗셈을 실행한 횟수: 3774


리스트의 원소와 복사

실습 2C-7 자료형을 정하지 않은 리스트 원소 확인하기

# 자료형을 정하지 않은 리스트 원소 확인하기


x = [15, 64, 7, 3.14, [32, 55], 'ABC']
for i in range(len(x)):
  print(f'x[{i}] = {x[i]}')
x[0] = 15
x[1] = 64
x[2] = 7
x[3] = 3.14
x[4] = [32, 55]
x[5] = ABC
# copy 후 원본 값 변경 시 copy의 값도 변경

x = [[1,2,3],[4,5,6]]
y = x.copy()          # x를 y로 얕은 복사
x[0][1] = 9
print(x)
print(y)
[[1, 9, 3], [4, 5, 6]]
[[1, 9, 3], [4, 5, 6]]
import copy         # deepcopy를 사용하기 위한 copy 모듈 임포트
x = [[1,2,3],[4,5,6]]
y = copy.deepcopy(x)
x[0][1] = 9
print(x)
print(y)
[[1, 9, 3], [4, 5, 6]]
[[1, 2, 3], [4, 5, 6]]

 

- 출처: Do it! 자료구조와 함께 배우는 알고리즘 입문 - 파이썬 편
- notebook ipynb file: https://github.com/heejvely/Algorithm/blob/main/Do_it_algorithm/Do_it_%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98_%EA%B8%B0%EB%B3%B8%20%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0%EC%99%80%20%EB%B0%B0%EC%97%B4.ipynb

 

GitHub - heejvely/Algorithm: 파이썬 알고리즘 인터뷰 책을 참고한 파이썬 알고리즘 연습

파이썬 알고리즘 인터뷰 책을 참고한 파이썬 알고리즘 연습. Contribute to heejvely/Algorithm development by creating an account on GitHub.

github.com

https://github.com/heejvely/Algorithm/blob/main/Do_it_algorithm/Do_it_%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98_%EA%B8%B0%EB%B3%B8%20%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0%EC%99%80%20%EB%B0%B0%EC%97%B4_2.ipynb

 

GitHub - heejvely/Algorithm: 파이썬 알고리즘 인터뷰 책을 참고한 파이썬 알고리즘 연습

파이썬 알고리즘 인터뷰 책을 참고한 파이썬 알고리즘 연습. Contribute to heejvely/Algorithm development by creating an account on GitHub.

github.com

 

728x90