" Park 기술 블로그 "
# 카테고리
# 도구
[C/C++] next_permutation 순열 구하기
2021-06-19 12:26:49

 오늘은 C/C++로 알고리즘을 풀 때 종종 사용되는 순열 구하는 방법에 대해서 정리하려 한다.

순열이란 쉽게 말해 특정 배열의 요소들로 만들 수 있는 조합들의 집합이라고 할 수 있다. 예를 들어 배열에 ['A', 'B', 'C'] 와 같이 담겨져 있을 경우 순열들은 "ABC", "ACB", "BAC", "BCA", "CAB", "CBA"가 될 수 있다. 굉장한 정성으로 직접 일일이 하드코딩 할 수 있긴 하지만 귀찮은건 참을 수 없으므로 필자는 더 쉬운 방법을 찾아 공부한다.

 

 C/C++에서는 이 순열을 아주 쉽게 사용할 수 있도록 미리 만들어진 next_permutation() 함수가 있다. algorithm.h 해더파일 안에 정의되어 있는 함수로 특정 구간 iterator를 아규먼트로 전달해주면 특정 구간의 요소들을 순열로 만들어 준다. 만약에 더 이상 순열의 경우가 없을 경우 false를 리턴하고 있을 경우 true를 리턴한다. 이 next_permutation() 함수를 사용하기 전에 중요한 요소가 있다. 바로 next_permutation()에 전달되는 특정 구간의 요소들은 오름차순으로 정렬되어 있어야한다.

 

 아래는 최근 풀었던 알고리즘 중 이 next_permutation() 함수를 활용해서 풀었던 문제다. 프로그래머스에서 직접 풀 수 있으며 2021 카카오 블라인드 테스트의 메뉴 리뉴얼 문제이다.

#include <bits/stdc++.h>
 
using namespace std;
 
bool compare(pair<string, int> p1, pair<string, int> p2) {
    return p1.second > p2.second;
}
 
vector<string> solution(vector<string> orders, vector<int> course) {
    vector<string> answer;
    
    unordered_map<string, int> courseMap;
    for (int i = 0; i < orders.size() - 1; i++) {
        for (int j = i + 1; j < orders.size(); j++) {
            vector<char> s;
            for (int k = 0; k < orders[j].length(); k++) {
                if (orders[i].find(orders[j][k]) != string::npos) s.push_back(orders[j][k]);
            }
            if (s.size() < 2) continue;
            
            for (int c = 0; c < course.size(); c++) {
                sort(s.begin(), s.end());
                do {
                    if (s.size() < course[c]) break;
                    string croped(s.begin(), s.begin() + course[c]);
                    vector<char> tmp(croped.begin(), croped.end());
                    sort(tmp.begin(), tmp.end());
                    string sorted(tmp.begin(), tmp.end());
                    courseMap[sorted]++;
                } while(next_permutation(s.begin(), s.end()));
            }
        }
    }
    
    for (auto it = courseMap.begin(); it != courseMap.end(); it++) it->second = 0;
    for (auto it = courseMap.begin(); it != courseMap.end(); it++) {
        for (int i = 0; i < orders.size(); i++) {
            string target = it->first;
            bool isEquals = true;
            for (int j = 0; j < target.length(); j++) {
                if (orders[i].find(target[j]) == string::npos) isEquals = false;
            }
            if (isEquals) courseMap[target]++;
        }
    }
    
    for (int i = 0; i < course.size(); i++) {
        vector<pair<string, int>> result;
        for (auto it = courseMap.begin(); it != courseMap.end(); it++) {
            if (it->first.length() == course[i] && it->second >= 2) {
                 result.push_back(*it);
            }
        }
        if (result.size() == 0) continue;
        
        sort(result.begin(), result.end(), compare);
        answer.push_back(result[0].first);
        for (int i = 1; i < result.size(); i++) {
            if (result[0].second == result[i].second) {
                answer.push_back(result[i].first);
            } else break;
        }
    }
    
    sort(answer.begin(), answer.end());
    return answer;
}

 22번째 줄처럼 next_permutation() 함수를 사용하기 전에 오름차순으로 정렬한 부분을 볼 수 있고 while 반복문을 통해 순열 경우의 수가 없을 때까지 반복해서 사용하고 있다. 이 문제는 아래의 링크에서 직접 풀어볼 수 있다.

https://programmers.co.kr/learn/courses/30/lessons/72411

0
# 댓글 + 새 댓글 작성
# 새 댓글 작성
댓글 암호는 댓글 삭제 시 필요합니다.
# 님에게 답변 작성
대댓글 암호는 댓글 삭제 시 필요합니다.
# 님의 댓글 삭제
댓글 작성 시 입력했던 암호를 입력해주세요.
아직 댓글이 없습니다