파이썬에서는 sort()
함수를 사용하면 쉽게 정렬이 되지만 여기서는 직접 구현해 문제를 풀어보겠다.
- 먼저 n개를 받아 몇개를 정렬할 것인지 받는다.
- 리스트 A에 입력데이터를 저장
- 이중 for문을 사용하여 현재 리스트의 값보다 1칸 오른쪽 리스트의 값이 더 작으면 두 수의 자리를 바꾸어 준다.
A = [int(input()) for _ in range(N)]를 사용하여 반복문을 사용하지 않고 한번에 입력 받음
💻 코드
N = int(input())
# A = [0] * N # 반복문으로 입력을 받을 수도 있지만 아래와 같이 한번에 입력을 받을 수 있다.
# for i in range(N):
# A[i] = int(input())
A = [int(input()) for _ in range(N)]
for i in range(N-1): # N개의 수를 두개씩 비교하면 N-1번 반복하게 됨
for j in range(N-1-i): # N-1-i만큼 반복
if A[j] > A[j+1]:
temp = A[j]
A[j] = A[j+1]
A[j+1] = temp
for i in range(N):
print(A[i])
이 문제는 버블 정렬의 swap이 일어나지 않은 개수를 세는 문제이다. 하지만 이 문제를 버블 정렬로 문제를 풀면 N의 최대 범위가 5000,000이므로 시간 초과가 발생한다. 따라서 안쪽 for문이 몇 번 수행됐는지 구하는 다른 아이디어가 필요하다.
안쪽 for 문이 몇 번 수행 됐는지 구하는 다른 아이디어
- 안쪽 루프는 1에서 n - j (책에서는 n - j 라고 나와있는데 내 생각은 n - i 인 것 같다) 까지 즉 왼쪽에서 오른쪽으로 이동하면서 swap을 수행한다.
- 이는 특정 데이터가 안쪽 루프에서 swap의 왼쪽으로 이동할 수 있는 최대 거리가
1 이라는 뜻이다. 즉, 데이터의 정렬 전 index와 정렬 후 index를 비교해 왼쪽으로 가장 많이 이동한 값을 찾으면 이 문제를 시간 초과없이 풀 수 있다.
따라서 정렬 전 index - 정렬 후 index 값 중 최대값을 찾아 왼쪽으로 몇 칸 이동 했는지 구할 수 있다. 그리고 swap이 일어나지 않는 반복문이 한 번 더 실행되는 것을 감안하여 최대값에 1을 더한다.
처음 알게된 사실
sort()와 sorted()의 차이
- sort()는
A.sort()
와 같이 원본 A를 정렬 시킨다.- sorted()는
변수 = sorted(A)
처럼 변수에 정렬 된 리스트를 저장하고 A는 원본 리스트를 계속 가지고 있다.
💻 코드
import sys
input = sys.stdin.readline
N = int(input())
A =[]
for i in range(N):
A.append((int(input()), i)) # 인덱스 순서를 알기 위해 인덱스 값과 리스트 값 동시 입력 받음
no_sort = 0
sorted_A = sorted(A) # sort()와 sorted() 차이가 있다.
for i in range(N):
if no_sort < sorted_A[i][1] - i: # 정렬 전 index - 정렬 후 index 계산의 최댓값 저장
no_sort = sorted_A[i][1] - i
print(no_sort + 1) # 정렬이 다 완료 된 후 한번 더 for문을 돌기 때문에 1을 더해줌
선택 정렬 과정
- 남은 정렬 부분에서 최솟값 또는 최댓값을 찾는다.
- 남은 정렬 부분에서 가장 앞에 있는 데이터와 선택된 데이터를 swap한다.
- 가장 앞에 있는 데이터의 위치를 변경해(index++) 남은 정렬 부분의 범위를 축소한다.
- 전체 데이터 크기만큼 index가 커질 때까지, 즉 남은 정렬 부분이 없을 때까지 반복한다.
💻 코드
import sys
input = sys.stdin.readline
print = sys.stdout.write
A = list(input())
for i in range(len(A)):
Max = i # Max 변수에 첫번째 i 값 임시로 넣음
for j in range(i+1, len(A)): # i값 다음의 값부터 비교
if A[j] > A[Max]: # j값이 Max값보다 크다면
Max = j
if A[i] < A[Max]: # Max 값을 맨 처음 i값으로 정렬 시켜주는 작업
temp = A[i]
A[i] = A[Max]
A[Max] = temp
for i in range(len(A)):
print(A[i])
삽입 정렬 과정
- 현재 index에 있는 데이터 값을 선택한다.
- 현재 선택한 데이터가 정렬된 데이터 범위에 삽입될 위치를 탐색한다.
- 삽입 위치부터 index에 있는 위치까지 shift 연산을 수행한다.
- 삽입 위치에 현재 선택한 데이터를 삽입하고 index++ 연산을 수행한다.
- 전체 데이터의 크기만큼 index가 커질 때까지, 즉 선택할 데이터가 없을 때까지 반복한다.
적절한 삽입 위치를 탐색하는 부분에서 이진 탐색(binary search) 등과 같은 탐색 알고리즘을 사용하면 시간 복잡도를 줄일 수 있다.
이 문제는 ATM 앞에 있는 사람 중 인출 시간이 가장 적게 걸리는 사람이 맨 앞에 올수록 시간의 합이 가장 작게 된다.
N의 최댓값이 1,000이고 시간 제한이 1초이기 때문에 시간 복잡도 인 알고리즘 어떤 것도 사용 가능하다.
💻 코드
import sys
input = sys.stdin.readline
N = int(input())
A = list(map(int, input().split()))
S = [0] * N
for i in range(1, N): # 0번째는 의미가 없으니 1부터 N까지
insert_point = i # 삽입 인덱스 번호 초기화
insert_value = A[i] # 인덱스 값 초기화
for j in range(i-1, -1, -1): # i-1 부터 0까지 뒤에서부터 크기 비교
if A[j] < A[i]:
insert_point = j + 1
break
if j == 0: # 현재 비교하는 인덱스 값이 가장 작을 때
insert_point = 0
for j in range(i, insert_point, -1): # i부터 inser_point까지 뒤에서 부터 인덱스를 한칸 밀기
A[j] = A[j-1]
A[insert_point] = insert_value # 현재 인덱스 값 삽입 위치에 넣기
S[0] = A[0] # 0번 인덱스 값은 그대로 넣기
for i in range(1, N): # 합 배열
S[i] = S[i-1] + A[i]
sum = 0
for i in range(0, N): # 합 배열 총합
sum += S[i]
print(sum)