반응형
반응형

0. 문제

어떤 수를 소인수분해 했을 때 그 소인수가 2 또는 3 또는 5로만 이루어진 수를 Ugly Number라고 부릅니다. Ugly Number를 차례대로 적어보면
1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, .......입니다. 숫자 1은 Ugly Number의 첫 번째 수로 합 니다. 자연수 N이 주어지면 Ugly Number를 차례로 적을 때 N번째 Ugly Number를 구하는 프로그램을 작성하세요.

  1. 입력설명

    • 첫 줄에 자연수 N(3<=N<=1500)이 주어집니다.
  2. 출력 설명

    • 첫 줄에 N번째 Ugly Number를 출력하세요.
  3. 입력 예제1

    • 10
  4. 출력 예제1

    • 12
  5. 입력 예제2

    • 1500
  6. 출력 예제2

    • 859963392
  7. 문제 풀이 핵심

    • vector(또는 배열)에 ugly number를 순서대로 입력 한다.
    • ugly number는 2,3,5를 이용해 작은 값 순서대로 입력한다.

1. 풀이1 : vector에 ugly number를 순서대로 입력한다.

  1. p2,p3,p5 변수를 생성하여 vector의 제일 앞을 가리킨다.
    • p2,p3,p5 는 각각 vector를 가리키는 인덱스 값
  2. p2,p3,p5 가 각각 가리키는 값을 곱하여 최소값을 구한다.
    • p2V = vector[p2] * 2 : p2가 가리키는 uglynumber에 2를 곱함
    • p3V = vector[p3] * 3 : p3가 가리키는 uglynumber에 3를 곱함
    • p5V = vector[p5] * 2 : p5가 가리키는 uglynumber에 5를 곱함
  3. p2V, p3V, p5V의 최소값을 vector에 넣는다.
  4. 최소값을 가리키는 인덱스는 1증가한다.
    • 만약 p2V가 가장 작으면, p2 에 +1을 한다.
    • 만약 여러 개(p2V,p3V 등) 이 동시에 가장 작으면 , p2,p3에 +1을 한다.
  5. 최종적으로 입력받은 number에 해당하는 vector값을 출력한다.
#include<iostream>
#include<vector>
int p2 = 0, p3 = 0, p5 = 0;
int p2V, p3V, p5V;
std::vector<int> vecData;

// 최소값 구하기
int findMin() {
    int min = 0;
    p2V = vecData[p2] * 2;
    p3V = vecData[p3] * 3;
    p5V = vecData[p5] * 5;

    if (p2V <= p3V) {
        if (p2V <= p5V) {
            min = p2V;
        }
        else {
            min = p5V;
        }
    }
    else {
        if (p3V <= p5V) {
            min = p3V;
        }
        else {
            min = p5V;
        }
    }
    return min;
}

int main() {
    int n;
    scanf_s("%d", &n);
    int data;
    vecData.push_back(1);
    for (int i = 1; i < n; i++) {
        int min = findMin();
        if (min >= p2V) {
            p2++;
            data = p2V;
        }
        if (min >= p3V) {
            p3++;
            data = p3V;
        }
        if (min >= p5V) {
            p5++;
            data = p5V;

        }
        vecData.push_back(data);
    }
    std::cout << vecData.back() << std::endl;
    return 0;
}
  1. 예시

참고

  1. it 취업을 위한 알고리즘 문제풀이 (with C/C++) : 코딩테스트 대비
반응형
반응형

0. 문제

세종대왕은 현수에게 현수가 다스릴 수 있는 영지를 하사하기로 했다. 전체 땅은 사각형으로 표시된다. 그 사각형의 땅 중에서 세종대왕이 현수가 다스릴 수 있는 땅의 크기(세로의 길이와 가
로의 길이)를 정해주면 전체 땅 중에서 그 크기의 땅의 위치를 현수가 정하면 되는 것이다.
전체 땅은 사각형의 모양의 격자로 되어 있으며, 그 사각형 땅 안에는 많은 오렌지 나무가 심겨져 있다. 현수는 오렌지를 무척 좋아하여 오렌지 나무가 가장 많이 포함되는 지역을 선택하고 싶어 한다. 현수가 얻을 수 있는 영지의 오렌지 나무 최대 개수를 출력하는 프로그램을 작성하세요. 다음과 같은 땅의 정보가 주어지고, 현수가 하사받을 크기가, 가로 2, 세로 3의 크기이면 가장 많은 오렌지 나무가 있는 영지는 총 오렌지 나무의 개수가 16인 3행 4열부터 시작하는 구역이다.

  1. 입력설명

    • 첫 줄에 H(세로길이)와 W(가로길이)가 입력된다. (5<=H, W<=50) 그 다음 H줄에 걸쳐 각 사각형 지역에 오렌지의 나무 개수(1~9개) 정보가 주어진다.
    • 그 다음 영지의 크기인 세로길이(1H)와 가로길이(1W)가 차례로 입력된다.

2) 출력 설명

  • 첫 줄에 현수가 얻을 수 있는 오렌지 나무의 최대 개수를 출력한다.

3) 입력 예제1

  • 6 7
  • 3 5 1 3 1 3 2
  • 1 2 1 3 1 1 2
  • 1 3 1 5 1 3 4
  • 5 1 1 3 1 3 2
  • 3 1 1 3 1 1 2
  • 1 3 1 3 1 2 2
  • 2 3
  1. 출력 예제1

    • 16
  2. 문제 풀이 핵심

    • DP 테이블을 구한다.
    • DP 테이블을 이용해 면적을 계산한다.

1. 풀이1 : DP 테이블을 구한다.

  1. DP 테이블을 구함
    • i,j 번째 DP 테이블은 아래와 같이 구할 수 있다.
  2. DP 테이블을 이용하여 영지크기를 계산한다.
    • i,j 번째 영지 크기는 아래와 같이 구할 수 있다.
#include<vector>
#include<algorithm>
using namespace std;

int a[701][701], dy[701][701];
int main() {
    int h, w, n, m, i, j, tmp, max = -2147000000;
    scanf_s("%d %d", &h, &w);
    for (i = 1; i <= h; i++) {
        for (j = 1; j <= w; j++) {
            scanf_s("%d", &a[i][j]);
            dy[i][j] = dy[i - 1][j] + dy[i][j - 1] - dy[i - 1][j - 1] + a[i][j];
        }
    }

    scanf_s("%d %d", &n, &m);
    for (i = n; i <= h; i++) {
        for (j = m; j <= w; j++) {
            tmp = dy[i][j] - dy[i - n][j] - dy[i][j - m] + dy[i - n][j - m];
            if (tmp > max) max = tmp;
        }
    }
    printf("%d\n", max);
    return 0;
}

참고

  1. it 취업을 위한 알고리즘 문제풀이 (with C/C++) : 코딩테스트 대비
반응형
반응형

0. 문제

지니레코드에서는 불세출의 가수 조영필의 라이브 동영상을 DVD로 만들어 판매하려 한다.
DVD에는 총 N개의 곡이 들어가는데, DVD에 녹화할 때에는 라이브에서의 순서가 그대로 유지되어야 한다. 순서가 바뀌는 것을 우리의 가수 조영필씨가 매우 싫어한다. 즉, 1번 노래와 5번
노래를 같은 DVD에 녹화하기 위해서는 1번과 5번 사이의 모든 노래도 같은 DVD에 녹화해야 한다.
지니레코드 입장에서는 이 DVD가 팔릴 것인지 확신할 수 없기 때문에 이 사업에 낭비되는 DVD를 가급적 줄이려고 한다. 고민 끝에 지니레코드는 M개의 DVD에 모든 동영상을 녹화하기로 하였다. 이 때 DVD의 크기(녹화 가능한 길이)를 최소로 하려고 한다. 그리고 M개의 DVD는 모두 같은 크기여야 제조원가가 적게 들기 때문에 꼭 같은 크기로 해야 한다.

  1. 입력설명

    • 첫째 줄에 자연수 N(1≤N≤1,000), M(1≤M≤N)이 주어진다. 다음 줄에는 조영필이 라이브에서 부른 순서대로 부른 곡의 길이가 분 단위로(자연수) 주어진다. 부른 곡의 길이는 10,000분을 넘지 않는다고 가정하자.
  2. 출력 설명

    • 첫 번째 줄부터 DVD의 최소 용량 크기를 출력하세요.
  3. 입력 예제1

    • 9 3
    • 1 2 3 4 5 6 7 8 9
  4. 출력 예제1

    • 17
  5. 문제 풀이 핵심

    • 입력값을 모두 더한 값을 sum, DVD 개수를 m이라고 했을 때 정답은 sum / m ~ sum 안에 존재한다고 가정한다.
    • 시작값 : sum / m, 끝값 : sum 으로 잡고 이분 검색 방법으로 정답을 찾는다.

1. 풀이1 : 정답의 범위를 정해놓고, 정답을 이분 검색으로 찾아 나가자!

  1. 입력
    • 데이터 개수 저장 : n
    • DVD 개수 저장 : m
    • 데이터 저장 : data
    • 입력 받을 때 합계 sum 저장
  2. 정답 가능한 시작값 설정
    • lt = sum / m;
  3. 정답 가능한 끝값 설정
    • rt = sum;
  4. mid값이 정답 가능한지 확인
    • mid = (lt + rt) / 2
    • 가능하다면, mid보다 큰값은 무조건 가능하므로, rt = mid -1 하면서 solution 변수에 mid값을 저장
    • 안된다면, mid보다는 커야 하므로, lt = mid + 1
    • 4를 반복하다가 lt와 rt가 엇갈리면 중단하고 solution 을 출력
  5. 주의 할점
    • 가능 여부 판단 시에 mid는 반드시 값의 max값 보다 커야함
    • DVD 용량이 음악 1곡의 크기보다 커야만 저장이 가능하기 때문
#include<iostream>
#include<vector>

int main() {
#include<iostream>
#include<vector>

bool isAvailable(std::vector<int> data, int mid, int num, int max) {
    int cnt = 1;
    int sum = 0;
    for (int i = 0; i < data.size(); i++) {
        sum += data[i];
        if (mid < sum) {
            cnt++;
            sum = data[i];
        }
    }
    if (mid >= max && cnt <= num) {
        return true;
    }
    return false;
}

int main() {
    int n, m, sum = 0, max = 0;;

    scanf_s("%d %d", &n, &m);
    std::vector<int> data(n);
    for (auto& dd : data) {
        scanf_s("%d", &dd);
        sum += dd;
        if (max < dd) {
            max = dd;
        }
    }
    int lt = sum / m, rt = sum, mid, solution = sum;
    while (lt <= rt) {
        mid = (lt + rt) / 2;
        if (isAvailable(data, mid, m, max)) {
            solution = mid;
            rt = mid - 1;
        }
        else {
            lt = mid + 1;
        }
    }

    std::cout << solution;
    return 0;
}
  1. 예시

    • 입력 : 9, 3
    • 데이터 : 1 2 3 4 5 6 7 8 9
    • sum = 45, m = 3
    • 정답은 45 / 3 = 15 ~ 45 사이에 존재
    • 중간 값인 60/2 = 30 이 가능한지 확인
    • 가능하므로 범위는 15 ~ 29, sol 변수에 30 저장
    • 중간 값인 44/2 = 22 가 가능한지 확인
    • 가능하므로 범위는 15 ~ 21, sol 변수에 22 저장
    • 중간 값인 36/2 = 18 이 가능한지 확인
    • 가능 하므로 범위는 15 ~ 17, sol 변수에 18 저장
    • 중간 값인 32/2= 16 이 가능한지 확인
    • 불가능 하므로 범위는 17~17
    • 중간 값인 34/7 = 17 이 가능한지 확인
    • 가능하므로 범위는 17 ~ 16, sol 변수에 17 저장
    • lIdx와 rIdx가 엇갈리므로 빠져나오고 sol변수에 저장된 17이 정답

참고

  1. it 취업을 위한 알고리즘 문제풀이 (with C/C++) : 코딩테스트 대비
반응형
반응형

0. 문제

입력으로 양의 정수 N이 입력되면 2개 이상의 연속된 자연수의 합으로 정수 N을 표현하는 방법의 가짓수를 출력하는 프로그램을 작성하세요.
만약 N=15이면
7+8=15
4+5+6=15
1+2+3+4+5=15
와 같이 총 3가지의 경우가 존재한다.

  1. 입력설명

    • 첫 번째 줄에 양의 정수 N(7<=N<1000)이 주어진다.
  2. 출력 설명

    • 첫줄부터 각각의 경우의 수를 출력한다. 맨 마지막 줄에 총 개수를 출력한다
  3. 입력 예제1

    • 15
  4. 출력 예제1

    • 7 + 8 = 15
    • 4 + 5 + 6 = 15
    • 1 + 2 + 3 + 4 + 5 = 15
    • 3
  5. 문제 풀이 핵심

    • 2개 연속된 수의 경우 숫자에서 1,2를 뺀 값이 2로 나누어지는지 확인한다.
    • 3개 연속된 수의 경우 숫자에서 1,2,3을 뺀 값이 3으로 나누어지는지를 확인한다.
    • 반복한다.

1. 풀이1 : 오른쪽으로 +1 왼쪽으로 -1을 반복하자.

  1. 방법 요약
    • 입력 변수(num)를 n(2~num)으로 나누고, 좌/우로 값을 번갈아 하나씩 연결시키며 더한다.(n 개수 만큼 연결)
    • 더한 값이 num과 같으면 기록하고, 커지면 break한다.
    • 반복하다가 왼쪽 값이 1이거나 오른쪽값이 num과 같아지면 그만한다.
#include<iostream>
#include<vector>

int main() {
#include<iostream>
#include<deque>
int main() {
    int num;
    scanf_s("%d", &num);

    int cnt = 0;
    int lIdx = 0, rIdx = 0;
    int n = 2;

    for (n = 2; n < num; n++) {
        int sum = 0;
        int mok = num / n;
        std::deque<int> result;
        bool flag = true;
        lIdx = mok;  rIdx = mok;
        int kk = 1;
        sum += mok;
        result.push_back(mok);
        while (kk < n) {
            if(flag){
                rIdx++;
                sum += rIdx;
                flag = false;
                result.push_back(rIdx);
            }
            else {
                lIdx--;
                sum += lIdx;
                flag = true;
                result.push_front(lIdx);
            }
            kk++;
            if (sum > num) break;
            else if (sum == num) {
                std::cout << result[0];
                for (int ii = 1; ii < result.size(); ii++) {
                    std::cout << " + " << result[ii];
                }
                std::cout << " = " << sum << std::endl;

                cnt++;
            }
            if (lIdx == 1 || rIdx == num) break;
        }

    }
    std::cout << cnt;
    return 0;
}
  1. 예시

    • 입력 : 15
    • 2로 나누어질 경우
    • 15 / 2 = 7 => 오른쪽하나 증가하여 8 , ==> {7,8}
    • 15 / 3 = 5 => 오른쪽하나 증가 6, 왼쪽하나 증가 4, ==> {4,5,6}
    • 15 / 4 = 3 => 오른쪽 하나 증가 4, 왼쪽하나 증가 2, 오른쪽하나 증가 5 ==> 2+3+4+5 != 15 이므로 (x)
    • 15 / 5 = 3 => 오른쪽 하나 증가 4, 왼쪽하나 증가 2, 오른쪽하나 증가 5, 왼쪽 하나 증가 1 ==> {1,2,3,4,5}
    • lIdx가 1이므로 멈춤

2. 풀이2 : n이 연속된 2개로 분리된다면, n에서 1,2 를 뺀값을 2로 나누어 떨어진다.

  1. 방법 요약
    • n = 2일 경우, 15 에서 1,2를 뺀 12를 2로 나누어 떨어진다.
    • 1,2에 12/2의 몫 6을 각각 더해주면 된다. ( 7,8 )
    • n = 3일 경우, 15에서 1,2,3을 뺀 9를 3으로 나누어 떨어진다.
    • 1,2,3에 9/3의 몫 3를 각각 더한다. (4,5,6)
    • 반복한다.
int main() {
#include<iostream>
using namespace std;

int main() {
    int a, b = 1, cnt = 0, tmp, i;
    scanf_s("%d", &a);
    tmp = a;
    a--;

    while (a > 0) {
        b++;
        a = a - b;
        if (a%b == 0) {
            for (i = 1; i < b; i++) {
                printf("%d + ", (a / b) + i);
            }
            printf("%d = %d\n", (a / b) + i, tmp);
            cnt++;
        }
    }
    printf("%d\n", cnt);
    return 0;
}
  1. 예시

    • 입력 : 15
    • n : 2일 경우
    • 15 에서 1,2를 뺀 12 / 2 는 나머지가 0이므로 1,2에 6을 더한 값이 정답 => {7,8}
    • n : 3일 경우
    • 15 에서 1,2,3를 뺀 9 / 3 은 나머지가 0이므로 1,2,3에 3을 더한 값이 정답 => {4,5,6}
    • 15 에서 1,2,3,4를 뺀 5 / 4 은 나머지가 1이므로 pass
    • 15에서 1,2,3,4,5를 뺀 0 / 5 는 나머지가 0이므로 1,2,3,4,5에 0을 더한 값이 정답 => {1,2,3,4,5}
    • a가 0이므로 멈추고 개수 출력

참고

  1. it 취업을 위한 알고리즘 문제풀이 (with C/C++) : 코딩테스트 대비
반응형
반응형

0. 문제

1부터 n까지의 수를 한 번씩만 사용하여 이루어진 수열이 있을 때, 1부터 n까지 각각의 수 앞에 놓여 있는 자신보다 큰 수들의 개수를 수열로 표현한 것을 Inversion Sequence라 한다.
예를 들어 다음과 같은 수열의 경우
4 8 6 2 5 1 3 7
1앞에 놓인 1보다 큰 수는 4, 8, 6, 2, 5. 이렇게 5개이고,
2앞에 놓인 2보다 큰 수는 4, 8, 6. 이렇게 3개,
3앞에 놓인 3보다 큰 수는 4, 8, 6, 5 이렇게 4개......
따라서 4 8 6 2 5 1 3 7의 inversion sequence는 5 3 4 0 2 1 1 0 이 된다.
n과 1부터 n까지의 수를 사용하여 이루어진 수열의 inversion sequence가 주어졌을 때, 원래 의 수열을 출력하는 프로그램을 작성하세요.

  1. 입력설명

    • 첫 번째 줄에 자연수 N(3<=N<100)이 주어지고, 두 번째 줄에는 inversion sequence가 숫자 사이에 한 칸의 공백을 두고 주어진다.
  2. 출력 설명

    • 오름차순으로 정렬된 수열을 출력합니다.
  3. 입력 예제1

    • 8
    • 5 3 4 0 2 1 1 0
  4. 출력 예제1

    • 4 8 6 2 5 1 3 7
  5. 문제 풀이 핵심

    • 입력 데이터 끝에서 부터 시작!
    • 입력 데이터의 값 만큼 앞으로 땡기고, 그 자리에 해당 숫자를 입력
    • 삽입 정렬!!

1. 풀이1 : 1부터 자기 위치에 저장하자!

  1. 입력
    • 사용자에게 num을 입력 받음
    • data vector를 num 개수 만큼 초기화
    • reuslt vector를 num 개수 만큼 101로 초기화(최대값이 100이므로)
  2. i = 0 ~ n-1 까지 반복
    • 숫자는 1부터 시작하므로 idx = i+1로 저장
  3. j = 0 ~ n-1 까지 반복
    • result[j] 가 idx보다 크면 개수를 +1
    • 개수가 data[i] + 1 과 같으면 break
  4. result[j] 에는 idx를 저장
  5. 반복이 끝나면 값 출력
#include<iostream>
#include<vector>

int main() {
    // 데이터 입력
    int num;
    scanf_s("%d", &num);
    std::vector<int> data(num);
    for (auto & dd : data) {
        scanf_s("%d", &dd);
    }

    std::vector<int> result(num,101);
    int j = 0;
    for (int i = 0; i < data.size(); i++) {
        int idx = i + 1;    // 해당 번호 저장(1~n)
        int cnt = 0;
        for (j = 0; j < result.size(); j++) {
            if (result[j] > idx) {
                cnt++;
            }
            if (cnt == data[i]+1) {
                break;
            }
        }
        result[j] = idx;
    }

    for (auto dd : result) {
        std::cout << dd << " ";
    }
    return 0;
}
  1. 예시

    • 입력 : 8
    • data : 5,3,4,0,2,1,1,0
    • result : 101,101,101,101,101,1,101,101
    • result : 101,101,101,2,101,1,101,101
    • result : 101,101,101,2,101,1,3,101
    • result : 4,101,101,2,101,1,3,101
    • result : 4,101,101,2,5,1,3,101
    • result : 4,101,6,2,5,1,3,101
    • result : 4,101,6,2,5,1,3,7
    • result : 4,8,6,2,5,1,3,7

2. 풀이2 : 뒤에서 부터 저장하자!

  1. 입력
    • 사용자에게 num을 입력 받음
    • data vector를 num 개수 만큼 초기화
    • reuslt vector를 num 개수 만큼 101로 초기화(최대값이 100이므로)
  2. i는 끝에서부터 시작까지 반복
    • j는 i에서 시작하여 data[i]의 개수만큼 데이터를 앞으로 땡김
    • result[j] 에 idx를 저장
int main() {
    int num;
    scanf_s("%d", &num);

    std::vector<int> data(num);
    std::vector<int> result(num);

    for (auto & dd : data) {
        scanf_s("%d", &dd);
    }

    int i = 0, j = 0, idx;

    for (i = data.size() - 1; i >= 0; i--) {
        idx = i + 1;
        for (j = i; j < i + data[i]; j++) {
            result[j] = result[j + 1];
        }
        result[j] = idx;
    }
    for (auto dd : result) {
        std::cout << dd << " ";
    }
    return 0;
}
  1. 예시

    • 입력 : 8
    • data : 5,3,4,0,2,1,1,0
    • result : 0,0,0,0,0,0,0,8
    • result : 0,0,0,0,0,0,8,7
    • result : 0,0,0,0,0,8,6,7
    • result : 0,0,0,0,8,6,5,7
    • result : 0,0,0,4,8,6,5,7
    • result : 0,0,4,8,6,5,3,7
    • result : 0,4,8,6,2,5,3,7
    • result : 4,8,6,2,5,1,3,7

참고

  1. it 취업을 위한 알고리즘 문제풀이 (with C/C++) : 코딩테스트 대비
반응형
반응형

0. 요약

1. 이분 검색 이란?

  1. 정렬된 데이터를 계속해서 반으로 나누어 빠르게 찾는 방법
  2. 복잡도 : O(logn)
  3. 사용 예시
    • 자료구조 내에 특정 값을 찾을 떄(vector에 30이 있는지)
    • 특정 값이 정답인지 추려나갈 때 사용(lt~rt사이에서 정답을 찾을 때)

2. 이분 검색 방법

  1. n개의 데이터를 정렬
  2. 양끝을 가리키는 포인터 생성
    • lt = 0번째 인덱스
    • rt = n-1번째 인덱스
  3. 가운데를 가리키는 포인터 생성
    • mid = (lt+rt) / 2
  4. mid 가 찾는 값(key) 인지 확인
    • 같다면 그 index(몇번째인지 출력시 index + 1)를 출력
    • mid가 key보다 크다면, rt를 mid - 1로 설정
    • mid가 key보다 작다면, lt를 mid + 1로 설정
    • 2~4를 반복
  5. lt 가 rt보다 크면 찾는 값이 없으므로 중단함

3. 예제

  1. 입력 데이터
    • 개수 8
    • 데이터 : 12, 23, 32, 57, 65, 81, 87, 99
    • 찾는 값 : 32
  2. lt = 0, rt = 7
    • mid = 3
    • data[mid] = 57 > 32
    • rt = mid -1 = 2
  3. lt = 0, rt = 2
    • mid = 1
    • data[mid] = 23 < 32
    • lt = mid + 1 = 2
  4. lt = 2, rt = 2
    • mid = 2
    • data[mid] = 32 == 32
  5. 찾는 인덱스는 mid+2 = 3번째 인덱스

4. 소스

#include<iostream>
#include<vector>
#include<algorithm>
int main() {
    int cnt, num;
    scanf_s("%d %d", &cnt, &num);

    std::vector<int> data(cnt);
    for (auto& dd : data) {
        scanf_s("%d", &dd);
    }

    std::sort(data.begin(), data.end());

    int lt = 0, rt = data.size() - 1, mid;
    while (1) {
        mid = (lt + rt) / 2;
        if (num == data[mid]) {
            std::cout << mid + 1;
            break;
        }
        else if (num > data[mid]) {
            lt = mid + 1;
        }
        else {
            rt = mid - 1;
        }
        if (lt > rt) {
            std::cout << "찾는 값 없음";
            break;
        }
    }
    return 0;
}

참고

  1. it 취업을 위한 알고리즘 문제풀이 (with C/C++) : 코딩테스트 대비
반응형

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

[Algorithm 이론] 1. 정렬  (0) 2021.03.15
반응형

0. 수치 알고리즘

  1. <numeric> 헤더에 포함됨

1. 수치 리스트

알고리즘 설명
x2=accumulate(b,e,x) x2는 x를 초기값으로 시작한 구간 [b,e) 순차열 원소의 합
x2=accumulate(b,e,x,f) x2는 x를 초기값으로 시작한 구간 [b,e) 순차열 원소의 누적. f를 누적에 사용
x2=inner_product(b,e,b2,x) x2는 x를 초기값으로 시작한 구간 [b,e)와 구간 [b2,b2+e-b)의 내적(두 순차열의 곱의 합)
x2=inner_product(b,e,b2,x,f1,f2) x2는 x를 초기값으로 시작한 구간 [b,e)와 구간 [b2,b2+e-b)의 모든 원소끼리 f2 연산 후 f1연산으로 총 연산한 결과
p=adjacent_difference(b,e,t) 구간 [b,e)의 인접 원소와의 차를 순차열 [t,p)에 저장
p=adjacent_difference(b,e,t,f) 구간 [b,e)의 인접 원소와의 연산을 순차열 [t,p)에 저장. f를 연산에 사용
p=partial_sum(b,e,t) 구간 [b,e)의 현재 원소까지의 합을 순차열 [t,p)에 저장
p=partial_sum(b,e,t,f) 구간 [b,e)의 현재 원소까지의 연산을 순차열 [t,p)에 저장. f를 연산에 사용

2. 상세 내용

  1. accumulate(b,e,x)
    • 순차열 원소의 합을 구함
vector<int> v = {10,20,30,40,50};
int sum = accumulate(v.begin(), v.end(), 0);
// sum = 150 = 0+10+20+30+40+50

int sum2 = accumulate(v.begin(), v.end(), 100);
// sum = 250 = 100+10+20+30+40+50+
  1. accumulate(b,e,x,f)
    • 순차열 원소에 f함수 적용 가능
    • f는 이항 함수
    • 함수에 따라 누적합,누적곱 등 연산 가능
// 1. Functor
template<typename T>
struct Plus{
   T operator() (const T& left, const T& right){
      return left+right;
   }
};

// 2. 클라이언트
void main(){
   vector<int> v = {1,2,3,4,5};
   // 사용자가 정의한 합함수
   int a = accumulate(v.begin(), v.end(), 0, Plus<int>());
   // a = 15 = 0+1+2+3+4+5

   // stl multiplies
   int mul = accumulate(v.begin(), v.end(), 1, multiplies<int>());
   // mul = 120 = 1 * 1 * 2 * 3 * 4 * 5
}
// 3. 서버
T accumulate(Iterator first, Iterator last, T x, Function fun){
   T ret = x;
   for(Iterator p = first; p != last ; ++p){
      ret = fun(ret, *p);
   }
   return ret;
}
  1. inner_product(b,e,b2,x)
    • 두 순차열의 내적 계산
vector<int> v1 = {1,2,3,4,5};
vector<int> v2 = {2,2,2,2,2};

int in = inner_product(v1.begin(), v1.end(), v2.begin(), 100);
// in = 130 = 100 + 1*2 + 2*2 + 3*2 + 4*2 + 5*2
  1. inner_product(b,2,b2,x,f1,f2)
    • 다양한 원소 간의 연산과 누적 연산 수행 가능
    • 두 순차열의 원소끼리의 차이의 합을 계산하는 예제
int Plus(int left, int right){
   return left+right;
}

int Minus(int left, int right){
   return left-right;
}

vector<int> v1 = {10,20,30,40,50};
vector<int> v2 = {2,2,2,2,2};

int a = inner_product(
   v1.begin(), v1.end()
   , v2.begin(), 0, Plus, Minus);
// a = 140 = 0 + 10 -2 + 20 - 2 + 30 -2 + 40 -2 + 50 - 2

//서버 예시
T inner_product(Iter first, Iter first2, T x, Func1 fun1, Func2 fun2){
   T ret = x;
   for(Iter p = first, q = first2; p != last; ++p, ++q){
      ret = fun1(ret, fun2(*p,*q))
   }
   return ret;
}
  1. adjacent_difference(b,e,t)
    • 순차열에서 연속한 원소 간의 차 계산
vector<int> v1 = {10,20,30,40,50};
vector<int> v2(5);
auto iter = adjacent_difference(
   v1.begin(), v1.end(), v2.begin()
);
// v2 = {10, 10, 10, 10, 10}
// 1번 10 => 10
// 2번 10 => 20 - 10
// ...
// iter - 1 = > 마지막 10을 가리킴
  1. adjacent_difference(b,e,t,f)
    • 인접 원소와의 사용자 정의 함수 수행
    • EX) 인접 원소 합을 저장
int Plus(int left, int right){
   return left + right;
}

vector<int> v1 = {10,20,30,40,50}
vector<int> v2(5);
auto iter = adjacent_difference(
   v1.begin(), v1.end(), v2.begin(), Plus
);
// v2 = {10, 30, 50, 70, 90}
// 10 => 10
// 30 => 10 + 20
// ...
// iter - 1 = 90을 가리킴
  1. partial_sum(b,e,t)
    • 순차열에서 시작부터 매 현재 원소까지의 합을 구함
vector<int> v1 = {10,20,30,40,50};
vector<int> v2(5);

auto iter = partial_sum(
   v1.begin(), v1.end(), v2.begin()
);
// v2 = {10, 30, 60, 100, 150}
// 10 => 10
// 30 => 10 + 20
// 60 => 10 + 20 + 30
// ...
// iter - 1 => 150을 가리킴
  1. partial_sum(b,e,t,f)
    • 순차열에서 시작부터 매 현재 원소까지의 사용자 정의 연산을 수행함
int Multi(int left, int right){
   return left * right;
}

vector<int> v1 = {10,20,30,40,50};
vector<int> v2(5);

auto iter = partial_sum(v1.begin(), v1.end(), v2.begin(), Multi);
// v2 = { 10, 200, 6000, 240000, 12000000}
// 10 => 10
// 200 => 10 * 20
// 6000 => 10 * 20 * 30
// ...
// iter - 1 => 12000000을 가리킴

참고

  1. 뇌를 자극하는 C++ STL
반응형
반응형

0. 정렬된 범위 알고리즘

  1. 정렬된 구간에서만 동작하는 알고리즘
  2. 원소가 같음 비교시 a==b 연산 사용 안함
  3. 원소가 같은 비교시 !(a<b) && !(b<a) 사용

1. 정렬 알고리즘 리스트

알고리즘 설명
binary_search(b,e,x) 구간 [b,e)의 순차열에 x와 같은 원소가 있는가?
binary_search(b,e,x,f) 구간 [b,e)의 순차열에 x와 같은 원소가 있는가? f를 비교에 사용
includes(b,e,b2,e2) 구간 [b2,e2)의 모든 원소가 구간 [b,e)에도 있는가?
includes(b,e,b2,e2,f) 구간 [b2,e2)의 모든 원소가 구간 [b,e)에도 있는가? f를 비교에 사용
p=lower_bound(b,e,x) p는 구간 [b,e) 순차열에서 x와 같은 첫 원소의 반복자
p=lower_bound(b,e,x,f) p는 구간 [b,e) 순차열에서 x와 같은 첫 원소의 반복자. f는 비교에 사용
p=upper_bound(b,e,x) p는 구간 [b,e) 순차열에서 x 보다 큰 첫 원소의 반복자
p=upper_bound(b,e,x,f) p는 구간 [b,e) 순차열에서 x 보다 큰 첫 원소의 반복자. f를 비교에 사용
pair(p1,p2)=equal_range(b,e,x) 구간 [p1,p2)의 순차열은 구간 [b,e)의 순차열에서 x와 같은 원소의 구간. [lower_bound(), upper_bound())의 순차열과 같음
pair(p1,p2)=equal_range(b,e,x,f) equal_range(b,e,x)와 동일. f를 비교에 사용
p=merge(b,e,b2,e2,t) 구간[b,e)의 순차열과 구간 [b2,e2)의 순차열을 합병해 [t,p)에 저장
p=merge(b,e,b2,e2,t,f) merge(b,e,b2,e2,t)과 동일. f를 비교에 사용
inplace_merge(b,m,e) 정렬된 [b,m) 순차열과 [m,e) 순차열을 [b,e)순차열로 합병
inplace_merge(b,m,e,f) inplace_merge(b,m,e,f)와 동일. f를 비교에 사용
p=set_union(b,e,b2,e2,t) 구간 [b,e)의 순차열과 [b2,e2)의 순차열을 정렬된 합집합으로 [t,p)에 저장
p=set_union(b,e,b2,e2,t,f) set_union(b,e,b2,e2,t)와 동일. f를 비교에 사용
p=set_intersection(b,e,b2,e2,t) 구간 [b,e)의 순차열과 [b2,e2)의 순차열을 정렬된 교집합으로 [t,p)에 저장
p=set_intersection(b,e,b2,e2,t,f) set_intersection(b,e,b2,e2,t)과 동일. f를 비교에 사용
p=set_difference(b,e,b2,e2,t) 구간 [b,e)의 순차열과 [b2,e2)의 순차열을 정렬된 차집합 [t,p)에 저장
p=set_difference(b,e,b2,e2,t,f) set_difference(b,e,b2,e2,t)과 동일. f를 비교에 사용
p=set _symmetric_difference(b,e,b2,e2,t) 구간 [b,e)의 순차열과 [b2,e2)의 순차열을 정렬된 대칭 차집합으로 [t,p)에 저장
p=set _symmetric_difference(b,e,b2,e2,t,f) set _symmetric_difference(b,e,b2,e2,t)와 동일. f를 비교에 사용

2. 상세 예시

  1. binary_search(b,e,x)

    • 구간 [b,e)에서 x와 같은 원소가 있음 true
vector<int> v = {10,20,30,40,50};
bool b = binary_search(v.begin(), v.end(), 20);
// b = true
  1. binary_search(b,e,x,f)
    • f를 조건자(이항 함수)로 사용하여 찾음
bool Pred(int left, int right){
   return 3 < right - left;
} // 오른쪽이 왼쪽보다 3보다 크면 참

vector<int> v = {40,46,12,80,10,47,30,55,90,53};
sort(v.begin(), v.end(), Pred);
// 조건자에 의한 정렬
// v = {12,10,30,40,46,47,55,53,80,90}
// 12와 10의 차이가 3보다 작기 때문에 12가 앞
// 55와 53의 차이가 3보다 작기 때문에 55가 앞

bool b = binary_search(v.begin(), v.end(), 32, Pred);
// b = true
// !Pred(30,32) => true 이고,
// !Pred(32,30) => true 이므로,
// 참조건 (!Pred(30,32)&&!Pred(32,30)) = true
  1. includes(b,e,b2,e2)
    • [b,e) 에 [b2,e2)가 포함되면 true
vector<int> v = {10,20,30,40,50};
vector<int> v2 = {10,20,40};
vector<int> v3 = {10,20,60};

bool b1 = includes(v1.begin(), v1.end()
                  ,v2.begin(), v2.end());
// b1 = true
// v2는 v에 포함되므로

bool b2 = includes(v1.begin(), v1.end(), v2.begin(), v2.end());
// b2 = false
// v3의 60은 v에 포함되지 않으므로

//조건자 사용
sort(v1.begin(), v1.end(), greater<int>());
sort(v2.begin(), v2.end(), greater<int>());
b1 = includes(v1.begin(), v1.end()
            , v2.begin(), v2.end()
            , greater<int>())
  1. lower _bound, upper _bound, equal_range
    • 찾는 원소가 여러 개 일 때 반복자 반환
    • lower_bound : 첫 원소의 반복자 반환
    • upper_bound : 마지막 다음 원소 반복자 반환
    • equal_range : [lower_bound, upper_bound) pair 반환
vector<int> v = {10,20,30,30,30,40,50};

auto lower = lower_bound(v.begin(), v.end(), 30);
auto upper = upper_bound(v.begin(), v.end(), 30);
auto eual = equal_range(v.begin(), v.end(), 30);
// lower = 첫 30을 가리킴
// upper = 마지막 30의 다음 40을 가리킴
// eqaul = (lower,upper)의 pair 형태
  1. merge(b,e,b2,e2,t)
    • 정렬된 두 순차열을 목적지 순차열로 병합
vector<int> v1 = {10,20,30,40,50};
vector<int> v2 = {20,30,60};
vector<int> v3(10);

auto iter = merge(v1.begin(), v1.end()
                 ,v2.begin(), v2.end()
                 ,v3.begin());
// v3 = {10,20,20,30,30,40,50,60,0,0};
// iter -1 => 60을 가리킴
  1. inplace_merge(b,m,e)
    • 하나의 순차열이 두 구간으로 정렬되어 있을 때
    • 하나의 구간으로 정렬 가능
vector<int> v = {10,20,30,40,50,20,30,60};
// v => 10,20,30,40,50 과
// 20,30,60 의 두 개의 구간으로 정렬되어 있음

inplace_merge(v.begin(), v.begin()+5, v.end());
// v = {10,20,20,30,30,40,50,60} 으로 정렬됨

3. 집합 관련 알고리즘

  1. set_union(b,e,b2,e2,t)
    • 두 순차열의 합집합을 구함
  2. set_intersection(b,e,b2,e2,t)
    • 두 순차열의 교집합을 구함
  3. set_difference(b,e,b2,e2,t)
    • 두 순차열의 차집합을 구함
  4. set_ symmetric_difference(b,e,b2,e2,t)
    • 두 순차열의 대칭 차집합을 구함
vector<int> v1 = {10,20,30,40,50};
vector<int> v2 = {20,30,60};
vector<int> v3(10);

// 1. 합집합
auto iter = set_union(
   v1.begin(), v1.end()
  ,v2.begin(), v2.end()
  ,v3.begin());
// v3 = {10,20,30,40,50,60,0,0,0,0}
// iter - 1 => 60을 가리킴

// 2. 교집합
auto iter = set_intersection(
   v1.begin(), v1.end()
  ,v2.begin(), v2.end()
  ,v3.begin());
// v3 = {20,30,0,0,0,0,0,0,0,0}
// iter - 1 => 30을 가리킴

// 3.차집합
auto iter = set_difference(
   v1.begin(), v1.end()
  ,v2.begin(), v2.end()
  ,v3.begin());
// v3 = {10,40,50,0,0,0,0,0,0,0}
// iter - 1 => 50을 가리킴

// 4. 대칭 차집합
auto iter = set_symmetric_difference(
   v1.begin(), v1.end()
  ,v2.begin(), v2.end()
  ,v3.begin());
// v3 = {10,40,50,60,0,0,0,0,0,0}
// iter - 1 => 60을 가리킴

참고

  1. 뇌를 자극하는 C++ STL
반응형
반응형

0. 정렬 알고리즘

  1. 변경 알고리즘의 특수한 형태
  2. 특정 정렬 기준으로 원소의 순서를 변경 및 정렬

1. 정렬 알고리즘 리스트

알고리즘 설명
make_heap(b,e) 힙을 생성. 구간 [b,e)의 순차열을 힙 구조로 변경
make_heap(b,e,f) make_heap(b,e)와 동일. f는 조건자로 비교에 사용.
push_heap(b,e) 힙에 원소 추가. push_back와 같이 사용. 구간 [b,e)의 순차열을 다시 힘 구조가 되게 함.
push_heap(b,e,f) push_heap(b,e)와 동일. f는 조건자로 비교에 사용
pop_heap(b,e) 힙에서 원소 제거. 구간 [b,e)의 순차열의 가장 큰 원소(첫 원소)를 제거.
pop_heap(b,e,f) pop_heap(b,e)와 동일. f는 조건자로 비교에 사용.
sort_heap(b,e) 힙을 정렬. 구간 [b,e)의 순차열을 힙 구조를 이용해 정렬
sort_heap(b,e,f) sort_heap(b,e)와 동일. f는 조건자로 비교에 사용
nth_element(b,m,e) 구간 [b,e)의 원소 중 m-b개 만큼 선별된 원소를 [b,m) 순차열에 놓이게 함
nth_element(b,m,e,f) nth_element(b,m,e) 와 동일. f는 조건자로 비교에 사용
sort(b,e) 구간 [b,e)를 퀵 정렬 기반으로 정렬
sort(b,e,f) sort(b,e) 와 동일. 조건자 f를 사용해 정렬.
stable_sort(b,e) 구간 [b,e)를 머지 정렬을 기반으로 정렬. 값이 같은 원소의 상대적 순서 유지.
stable_sort(b,e,f) stable_sort(b,e)와 동일. f는 조건자로 비교에 사용.
partial_sort(b,m,e) 힙 정렬 기반으로 정렬. 구간 [b,e) 원소 중 m-b개 만큼 상위 원소를 정렬하여 [b,m) 순차열에 놓음
partial_sort(b,m,e,f) partial_sort(b,m,e) 와 동일. f는 조건자로 비교에 사용.
partial _sort_copy(b,e,b2,e2) 힙 정렬 기반으로 정렬. 구간 [b,e) 원소 중 상위 e2-b2개의 원소만 정렬하여 [b2,e2)로 복사
partial _sort_copy(b,e,b2,e2,f) partial _sort_copy(b,e,b2,e2)와 동일. f는 조건자로 비교에 사용.

2.힙 관련 알고리즘

  1. 자료 구조 힙
    • 완전 이진 트리로 구성
    • 트리 내의 모든 원소가 부모 노드보다 큰 값(또는 작은 값)을 가짐
    • 루트 노드는 항상 가장 작은 값(또는 가장 큰 값)을 가짐
    • 최대값, 최소값 연산이 빠름
  2. 힙의 연산
    • 추가 연산
      • 완전 이진 트리 가장 끝에 원소 추가
      • 힙의 규칙을 깨지 않게 교환하여 힙을 유지
    • 제거 연산
      • 루트 노드를 삭제
      • 삭제된 루트 노드에 힙의 마지막 노드 가져옴
      • 힙의 규칙 깨지 않게 교환하여 힙을 유지
  3. heap 예제
    • min heap : v = {1,3,2,4,6,5}
    • max heap : v = {6,5,3,4,2,1}
  4. make_heap(b,e)
    • 구간 [b,e)의 순차열을 힙 구조로 만듦
vector<int> v = {10,20,30,40,50,60};
// 1. 최대 heap 생성
make_heap(v.begin(), v.end());
// v = {60,50,30,40,20,10}

// 2. 최소 heap 생성
make_heap(v.begin(), v.end(), greater<int>());
// v= {10,20,50,30,40,60}
  1. push_heap(b,e)
    • 원소가 추가된 상태에서 사용
    • 추가된 구간 [b,e) heap을 교환하여 heap을 유지함.
    • 일반적으로 push_back()과 함께 사용
//위의 예제 수행 후
v.push_back(35);
// 마지막에 단순 원소 추가
// v = {60,50,30,40,20,10,35}
push_heap(v.begin(), v.end());
// v = {60,50,35,40,20,10,30}
// heap 형태를 재계산
  1. pop_heap(b,e)
    • root node를 (논리적)제거(제일 마지막으로 이동)
    • 원리
      • root node와 마지막 node를 교환
      • heap을 유지하도록 교환 반복
vector<int> v = {10,20,30,40,50,60};
make_heap(v.begin(), v.end());
// v = {60,50,30,40,20,10}
pop_hep(v.begin(), v.end());
// v= {50,40,30,10,20,60}
  1. sort_heap(b,e)
    • 구간 [b,e)를 heap 정렬
    • 구간 [b,e)가 heap 구조여야 함
vector<int> v = {10,20,30,40,50,60};
make_heap(v.begin(), v.end());
// v = {60,50,30,40,20,10}
sort_heap(v.begin(), v.end());
// v= {10,20,30,40,50,60}

3. 기타 정렬 알고리즘 상세

  1. nth_element(b,m,e)
    • 전체 구간 [b,e) 에서 구간 [b,m) 만큼의 순차열을 부분적으로 정렬
    • 주로 n 개의 요소를 선별할 때 사용
    • 또는 n 번째 요소가 필요할 때 사용
vector<int> v = {10,30,20,40,50,60};
nth_element(v.begin(), v.begin() + 1, v.end());
// 두번째로 작은 값 : v[1] = 20
  1. sort(b,e)
    • 퀵 정렬을 기반으로 정렬
vector<int> v = {5,1,3,2,7,9,8};
//오름차순 정렬(less: defualt)
sort(v.begin(), v.end());
// v = {1,2,3,5,7,8,9}

//내림차순 정렬(greater)
sort(v.begin(), v.end(), greater<int>());
// v = {9,8,7,5,3,2,1}
  1. stable_sort(b,e)
    • 머지 정렬을 기반으로 정렬
    • 같은 원소의 상대적인 순서를 유지할 때 사용
vector<int> v= {30,50,30,20,40,10,40};
//오름차순 정렬(less: defualt)
stable_sort(v.begin(), v.end());
// v = {10,20,30,30,40,40,50}

//내림차순 정렬(greater)
stable_sort(v.begin(), v.end(), greater<int>());
// v = {50,40,40,30,30,20,10}
  1. partial_sort(b,m,e)
    • heap정렬 기반으로 정렬
    • 순차열의 상위 구간만 정렬할 때 사용
    • heap정렬의 특징이 필요할 때 사용
    • m과 e가 같다면 전체 원소를 정렬함
vector<int> v = {10,30,20,40,50,60};
partial_sort(v.begin(), v.begin() + 3, v.end());
// v.begin() 부터 3개까지만 heap 정렬함
// v = {10,20,30,40,50,60}
  1. partial _sort_copy(b,e,b2,e2)
    • 구간 [b,e) 를 heap정렬 하고,
    • 구간 [b2,e2)에 정렬 결과를 저장함.
vector<int> v = {10,30,20,40,50,60};
vector<int> v2(3);
partial_sort_copy(v.begin(), v.end(), v2.begin(), v2.end());
// v.begin() 부터 3개까지만 heap 정렬함
// v2 = {10,20,30}

참고

  1. 뇌를 자극하는 C++ STL
  2. https://velog.io/@nninnnin7/HEAP
반응형
반응형

0. 변경 알고리즘

  1. 순차열 원소의 '순서'를 변경하는 알고리즘
    • 순차열의 원소를 교환
    • 순차열의 원소를 이동

1. 변경 알고리즘 리스트

알고리즘 설명
bool=next_permutation(b,e) 구간 [b,e)의 순차열을 사전순 다음 순열이 되게 함. 더 이상 다음 순열이 없는 마지막 순열이라면 bool은 false
bool=next_permutation(b,e,f) 구간 [b,e)의 순차열을 사전순 다음 순열이 되게 함. 비교에 f를 사용. 더 이상 다음 순열이 없는 마지막 순열이라면 bool은 false를 반환
bool=prev_permutation(b,e) 구간 [b,e)의 순차열을 사전순 이전 순열이 되게 함. 더 이상 이전 순열이 없는 첫 순열이라면 bool은 false를 반환
bool=prev_permutation(b,e,f) 구간 [b,e)의 순차열을 사전순 이전 순열이 되게 함. 비교에 f를 사용. 더 이상 이전 순열이 없는 첫 순열이라면 bool은 false
p=partition(b,e,f) 구간 [b,e)의 순차열 중 f(*p)가 참인 원소는 [b,p)의 순차열에 거짓인 원소는 [p,e)의 순차열로 분류
random_shuffle(b,e) 구간 [b,e)의 순차열을 랜덤(기본 랜덤기)로 뒤섞음
random_shuffle(b,e,f) 구간 [b,e)의 순차열을 f를 랜덤기로 사용하여 뒤섞음
reverse(b,e) 구간 [b,e)의 순차열을 뒤집음
p=reverse_copy(b,e,t) 구간 [b,e) 순차열을 뒤집어 목적지 순차열 [t,p)에 복사함
rotate(b,m,e) 구간 [b,e)의 순차열을 왼쪽으로 회전. 첫 원소와 마지막 원소가 연결된 것 처럼 모든 원소가 왼쪽으로 (m-b) 만큼 이동
p=rotate_copy(b,m,e,t) 구간 [b,e)의 순차열을 회전하여 목적지 순차열 [t,p)에 복사
stable_partition(b,e,f) partition() 알고리즘과 같고 원소의 상대적인 순서를 유지함

2. 상세 예시

  1. next_permutation(b,e)
    • 예시) v = 10,20,30
    • 6가지 순열을 만듦
vector<int> v = {10,20,30}
while(next_permutation(v.begin(), v.end())){
// 1. v = {10, 30, 20} , b = true
// 2. v = {20, 10, 30} , b = true
// 3. v = {20, 30, 10} , b = true
// 4. v = {30, 10, 20} , b = true
// 5. v = {30, 20, 10} , b = true
// 6. v = {10, 20, 30} , b = false
}
  1. next_permutation(b,e,f)
    • 이항 조건자 f를 기준으로 순열 만듦
bool Pred(const Point& left, const Point& right){
   return left.getY() < right.getY();
}  // Point의 y좌표가 오른쪽이 더 크면 true

vector<Point> v;
v.push_back(Point(5,1));
v.push_back(Point(7,2));
v.push_back(Point(5,3));

while(next_permutation(v.begin(), v.end(), Pred)){
   // 1. v = {(5,1), (5,3), (7,2)}, b = true
   // 2. v = {(7,2), (5,1), (5,3)}, b = true
   // 3. v = {(7,2), (5,3), (5,1)}, b = true
   // 4. v = {(5,3), (5,1), (7,2)}, b = true
   // 5. v = {(5,3), (7,2), (5,1)}, b = true
   // 6. v = {(5,1), (7,2), (5,3)}, b = false
}
  1. partition(b,e,f)
    • 순차열의 원소를 특정 조건에 따라 분류
    • 원리 : quick sort 에서 pivot 값을 기준으로 큰값과 작은값을 분류하듯 분류함
    • 30,40,50,10,20,60 => 30 그대로
    • 30,20,50,10,40,60 => 40,20 교환
    • 30,20,10,50,40,60 => 50,10 교환
bool Pred(int n){
   return n < 40;
} // 40 작으면 참

// 1. partition
vector<int> v = {30,40,50,10,20,60};
auto iter = partition(v.begin(), v.end(), Pred);
// v = 30,20,10,50,40,60
// iter -1 => 10을 가리킴
// [begin,iter) => {30,20,10}
// [iter,end) => {50,40,60}

// 2.stable_partition
vector<int> v2 = {30,40,50,10,20,60};
iter = stable_partition(v2.begin(), v2.end(), Pred);
// v = 30,10,20,40,50,60
// iter -1 => 20을 가리킴
// [begin,iter) => {30,10,20}
// [iter,end) => {40,50,60}
  1. stable_partition(b,e,f)

    • partition와의 차이 => 원소의 상대적인 순서를 변경안함
    • 위의 예제 참고
    • 원리
    • 30,40,50,10,20,60 => 30 그대로
    • 30,10,50,40,20,60 => 40, 10 교환
    • 30,10,20,40,50,60 => 50, 20 교환
  2. random_suffle(b,e)

    • 구간 [b,e)의 순차열을 랜덤으로 섞음
    • 초기화는 <cstdlib> 헤더의 srand() 사용
vector<int> v = {10,20,30,40,50};
random_shuffle(v.begin(), v.end());
// {50,20,40,30,10} : 랜덤으로 값 뒤섞임
  1. reverse(b,e)
    • 구간 [b,e)의 원소를 뒤집는다.
vector<int> v = {10,20,30,40,50};
reverse(v.begin(), v.end());
// v = {50,40,30,20,10}
  1. reverse_copy(b,e,t)
    • 뒤집은 순차열을 구간 [t,p)에 저장
vector<int> v1 = {10,20,30,40,50};
vector<int> v2(5);
auto iter = reverse_copy(v1.begin(), v1.end(), v2.begin());
// v2 = {50,40,30,20,10}
// iter - 1 => 10을 가리킴
  1. rotate(b,m,e)
    • 순차열을 회전
    • m 이 begin이 되고, (m-b) 만큼 이동함
vector<int> v = {10,20,30,40,50};

rotate(v.begin(), v.begin() + 2, v.end());
// v = {30,40,50,10,20} : 2만큼 회전
  1. rotate_copy(b,m,e,t)
    • 순차열을 회전하여 [t,p)에 복사
vector<int> v1 = {10,20,30,40,50};
vector<int> v2(5);
auto iter = rotate_copy(v1.begin(), v1.begin() + 2, v1.end(), v2.begin());
//v2 = {30,40,50,10,20}

참고

뇌를 자극하는 C++ STL

반응형

+ Recent posts

반응형