Notice
Recent Posts
Recent Comments
Link
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 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 |
Tags
- 인접 행렬
- 알고리즘
- 데이터베이스
- 파이썬
- #코드트리 #코딩테스트 #코테공부 #백트래킹 #알고리즘 기초
- 운영체제
- 플로이드-워셜
- 개발자루틴
- 코드트리
- 연결 리스트
- 항해99
- til
- 자료구조
- 프로그래밍 언어
- 코딩테스트사이트추천
- 자바
- 코딩테스트
- 코테공부
- Java
- 웹
- 프로그래머스
- 갭체크
- 티스토리챌린지
- 1일1코테
- 개발자취업
- 코딩테스트준비
- 오블완
- C
- 자바스크립트
- 99클럽
Archives
- Today
- Total
와드의 블로그
10972번: 다음 순열 본문
문제
1부터 N까지의 수로 이루어진 순열이 주어졌을 때, 사전순으로 다음에 오는 순열을 구하는 프로그램을 작성하는 문제입니다.
- 입력: 첫째 줄에 N (1 ≤ N ≤ 10,000)이 주어집니다. 둘째 줄에 순열이 주어집니다.
- 출력: 첫째 줄에 입력으로 주어진 순열의 다음에 오는 순열을 출력합니다. 만약 사전순으로 마지막에 오는 순열인 경우에는 -1을 출력합니다.
풀이: O(N) 시간 복잡도의 수학적 알고리즘 (Next Permutation)
N이 최대 10,000이므로 모든 순열을 생성하는 재귀(DFS) 방식은 사용할 수 없습니다. 현재 배열의 상태를 뒤에서부터 훑으며 단 한 번의 순회(O(N))만으로 다음 상태를 유추하는 알고리즘을 적용해야 합니다.
알고리즘 단계 분석
- 피벗 지점(i) 찾기: 배열의 뒤에서부터 탐색하며, a[i-1] < a[i]를 만족하는 가장 큰 인덱스 i를 찾습니다. 이는 순열의 뒷부분에서 내림차순이 끊기고 오름차순이 시작되는 지점을 찾는 과정입니다. 만약 i ≤ 0이라면 현재 순열이 이미 마지막(내림차순)이므로 1을 출력합니다.
- 교체 대상(j) 찾기: 다시 배열의 맨 뒤에서부터 탐색하며, 앞서 찾은 피벗 값인 a[i-1]보다 엄격히 큰 첫 번째 숫자 a[j]를 찾습니다.
- 값 교환 (Swap): a[i-1]과 a[j]의 위치를 서로 바꿉니다.
- 뒷부분 뒤집기 (Reverse): 인덱스 i부터 배열의 끝까지는 현재 내림차순 상태입니다. 이 구간을 뒤집어서 오름차순(가장 작은 사전순 상태)으로 만들면, a[i-1]보다 큰 수로 시작하는 가장 빠른 순열이 완성됩니다.
코드
import java.util.*;
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
int n = Integer.parseInt(br.readLine());
int[] a = new int[n];
StringTokenizer st = new StringTokenizer(br.readLine());
for (int i = 0; i < n; i++) {
a[i] = Integer.parseInt(st.nextToken());
}
// 다음 순열이 존재하면 결과 배열 출력, 없으면 -1 출력
if (nextPermutation(a)) {
for (int i = 0; i < n; i++) {
bw.write(a[i] + " ");
}
} else {
bw.write("-1");
}
bw.flush();
}
// 다음 순열을 생성하는 O(N) 알고리즘
static boolean nextPermutation(int[] a) {
int i = a.length - 1;
// 1. 뒤에서부터 a[i-1] < a[i]를 만족하는 첫 번째 인덱스 i 탐색
while (i > 0 && a[i - 1] >= a[i]) {
i--;
}
// i가 0 이하이면 마지막 순열임을 의미
if (i <= 0) {
return false;
}
// 2. 뒤에서부터 a[i-1] < a[j]를 만족하는 첫 번째 인덱스 j 탐색
int j = a.length - 1;
while (a[j] <= a[i - 1]) {
j--;
}
// 3. i-1과 j 위치의 값을 교환
swap(a, i - 1, j);
// 4. i부터 배열 끝까지를 뒤집어서 오름차순 상태로 만듦
j = a.length - 1;
while (i < j) {
swap(a, i, j);
i++;
j--;
}
return true;
}
// 배열의 두 요소를 교환하는 메서드
static void swap(int[] a, int i, int j) {
int tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
}
알고리즘 분류
수학 (Mathematics), 조합론 (Combinatorics), 구현 (Implementation)
'PS > B.O.J' 카테고리의 다른 글
| 11723번: 집합 (0) | 2026.05.01 |
|---|---|
| 10971번: 외판원 순회 2 (0) | 2026.04.30 |
| 1248번: Guess (1) | 2026.04.30 |
| 15661번: 링크와 스타트 (0) | 2026.04.29 |
| 14501번: 퇴사 (0) | 2026.04.29 |