danbibibi
article thumbnail
Published 2023. 2. 16. 17:58
next_permutation 구현 CS/알고리즘

Next Permutation

next permutation !  말 그 대로 다음 순열을 찾는 방법이다. 

= 현재 순열의 상태에서 크기순으로(사전 순) 다음에 올 수 있는 순열을 생성

 

구현에 들어가기 전에 기억 할 것

  • 첫 순열 = 오름차순
  • 마지막 순열 = 내림차순 

      → 모든 수가 내림차순으로 정렬되어 있다면, 순열을 모두 만들어 낸 것이고, 따라서 종료 조건이다!

 

그렇다면, Next Permutation을 어떻게 구현할까?

1. 뒤에서부터 역방향으로 탐색하면서 교환위치( i-1 , 오름차순이 깨지는 부분)을 찾는다.

💡 오름차순이 깨지는 부분이 교환 위치인 이유

자 예를 들어 ` int a = {1, 4, 9, 8, 3, 2,1}; ` 배열이 있다고 하자.
a[2] ~ a[6] 은 모두 내림차순으로 정렬되어 있다.
따라서, 더 이상 다음 순열이 발생할 수 없고,
새 순열을 만들기 위해서는 a[1] ~ a[6] 을 이용해서 만들어야 한다.

때문에, a[1] 이 교환 위치인 것이다.

 

2. 다시 뒤에서 부터 역뱡향으로 탐색하면서, 교환할 값의 위치(j)를 찾는다.

    이 때 교환할 값은 역방향으로 탐색할 때, 처음으로 등장하는 a[i-1] 보다 큰 수 이다.

💡 교환할 값의 위치를 위와 같이 정하는 이유는
    해당 순열보다 큰 순열들 중에서 가장 작은 순열을 찾기 위해서이다.

 

3. 두 값을 교환한다.

 

4. 교환위치 (i) 부터 맨 뒤 까지 오름차순으로 정렬한다.

💡 정렬 방법
앞서 2번에서, 교환할 값을 처음으로 등장하는 a[i-1]보다 큰수로 지정했다.
그렇다면, 역방향에서 볼 때, last_idx ~ i 까지의 부분 수열은 자동으로 오름차순이 된다.
따라서 (last_idx - i + 1) / 2 만큼 반복문을 돌면서 정렬해주면 된다! 자세한 건 코드를 보자!

 

 

 

구현

import java.util.*;

// nPn
public class PermutaitionNPTest {

	static int N, R;
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		N = sc.nextInt();
		R = sc.nextInt();

		int[] input = new int[N];
		for(int i=0; i<N; i++) input[i] = sc.nextInt();
		Arrays.sort(input); // 전처리 : 오름차순 정렬
		
		do {
			System.out.println(Arrays.toString(input));
			
		} while(np(input));
		
		sc.close();
	}
	
	private static boolean np(int[] input) {
		
		int n = input.length;
		
		// step1. 뒤쪽부터 꼭대기를 찾는다. (꼭대기 바로 앞이 교환할 자리)
		int i = n-1;
		while(i>0 && input[i-1]>=input[i]) --i;
		if(i == 0) return false;
		
		// step2. 꼭대기 바로 앞(i-1) 자리에 교환할 값을 뒤쪽부터 찾는다.
		int j = n-1;
		while(input[i-1]>=input[j]) --j;
		
		// step3. 꼭대기 바로 앞(i-1) 자리와 그 자리 값보다 한단계 큰 자리 (j) 수와 교환
		swap(input, i-1, j);
		
		// step 4. 꼭대기부터 맨 뒤 까지 오름차순으로 정렬
		int k= n-1;
		while(i<k) {
			swap(input, i++, k--);
		}

		return true;
	}
	
	private static void swap(int[] input, int i, int j) {
		int tmp = input[i];
		input[i] = input[j];
		input[j] = tmp;
	}
}

 

관련 문제

BOJ 5360번: Next Permutation

 

5360번: Next Permutation

Given an integer A, only other integers that are permutations of A are useful. All other numbers are useless. Find the next largest integer B, where the digits in B is a permutation of the digits of A. For example, suppose A=2413, then the next largest per

www.acmicpc.net

import java.io.*;
import java.util.*;

public class Main {
	
	static int N;
	static StringBuilder sb = new StringBuilder();

	public static void main(String[] args) throws Exception {
		// System.setIn(new FileInputStream("res/input.txt"));
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));		
		N = Integer.parseInt(br.readLine());
		
		String perm;
		for(int i=0; i<N; i++) {
			perm = br.readLine();
			sb.append(solution(perm)+"\n");
		}
		System.out.println(sb.toString());
		br.close();
	}

	static String solution(String perm) {
		
		int last_idx = perm.length()-1;
		char[] permArr = perm.toCharArray();
		
		// step 1 꼭대기를 찾음
		int i = last_idx;
		while(i>0 && permArr[i] <= permArr[i-1]) i--;
		if(i == 0) return "USELESS";
		
		// step 2 교환할 자리를 찾음
		int j = last_idx;
		while(j>0 && permArr[j] <= permArr[i-1]) j--;
		
		// step 3 swap
		swap(permArr, i-1, j);
		
		// step 4 sort
		int k = last_idx;
		while(i < k) swap(permArr, i++, k--);
		
		return new String(permArr);
	}
	
	static void swap(char[] permArr, int i, int j) {
		char tmp = permArr[i];
		permArr[i] = permArr[j];
		permArr[j] = tmp;
	}
}

 

'CS > 알고리즘' 카테고리의 다른 글

Binary Search (Lower Bound, Upper Bound)  (0) 2023.02.23
Union-Find (합집합 찾기)  (0) 2022.12.04
profile

danbibibi

@danbibibi

꿈을 꾸는 시간은 멈춰 있는 것이 아냐 두려워하지 마 멈추지 마 푸른 꿈속으로