https://www.acmicpc.net/problem/10972
N 길이의 순열이 주어질 때 그 다음 순열을 출력하고 만약 마지막 순열이었다면 -1을 출력하는 문제다. 처음에는 제한을 미처 보지 못하고 바로 파이썬에 내장된 permutations로 모든 순열을 만들어 맞는 것의 인덱스를 출력하게끔 했다. 하지만 이렇게 될 경우 1 <= N <= 10000, O(N^2) 때문에 메모리 초과, 시간 초과 등 여러 문제가 발생할 수 있다. 때문에 이번 문제에는 Next Permutation 알고리즘을 사용한다.
Next Permutation 알고리즘은 C++ 경우 stl에 내장되어 있지만 Python에는 그렇지 않으므로 직접 구현해야 한다. 이번 기회에 제대로 정리해두자.
문제의 예제 1번인 N = 4인 순열을 만들어보자.
이때, 첫 번째 순열은 1 2 3 4이며 아래와 같이 이어진다.
1 2 3 4 -> 1 2 4 3 -> 1 3 2 4 -> ... -> 4 3 2 1
1 2 3 4
-> 1 2 4 3
과정제일 뒤에서부터 탐색하여 앞 숫자가 뒷 숫자보다 작아지는 경우를 찾는다. 위 경우 (3, 4)
에서 찾을 수 있다. 이때 3
보다 큰 값이 나오는지 맨 뒤에서부터 찾기 시작하면 4
가 나온다. 이 둘을 스왑할 경우 1 2 4 3
이 된다.
1 2 4 3
-> 1 3 2 4
과정같은 방법으로 앞 숫자가 뒷 숫자보다 작아지는 경우를 찾는다. 위 경우 (2, 4)
에서 찾을 수 있다. 이때 2
보다 큰 값이 나오는지 맨 뒤에서부터 찾기 시작하며 이는 3
이다. 이때 이 둘의 값을 스왑하며 결과로는 1 3 4 2
가 나온다. 값을 바꾼 3
을 기준으로 1 3
4 2
로 나눈 뒤 앞의 값 1 3
과 뒤의 값을 정렬한 결과인 2 4
를 합친다. 결과적으로 1 3 2 4
가 나오게 된다.
따라서 다음 순열을 구하는 알고리즘은 아래와 같이 나타난다.
결과로 주어진 순열의 다음 순열을 구할 수 있다.
import sys
input = sys.stdin.readline
N = int(input())
arr = list(map(int, input().split()))
for i in range(N-1, 0, -1):
if arr[i-1] < arr[i]: # 앞 열의 값이 바로 뒷 열의 값보다 작으면
for j in range(N-1, 0, -1): # 그 앞 열의 값을 맨 뒷 열부터 비교
if arr[i-1] < arr[j]: # 그 앞 열의 값이 뒤에 있는 열보다 작을경우
arr[i-1], arr[j] = arr[j], arr[i-1] # 그 두 값을 스왑
arr = arr[:i] + sorted(arr[i:])
print(*arr)
exit()
print(-1)
아래는 참고한 홈페이지입니다. 감사합니다.
https://ji-gwang.tistory.com/262
https://velog.io/@tomato2532/NextPermutation