알고리즘/BAEKJOON

[백준] 18870번 좌표압축 -C++

hectick 2022. 2. 28. 18:26

https://www.acmicpc.net/problem/18870

 

18870번: 좌표 압축

수직선 위에 N개의 좌표 X1, X2, ..., XN이 있다. 이 좌표에 좌표 압축을 적용하려고 한다. Xi를 좌표 압축한 결과 X'i의 값은 Xi > Xj를 만족하는 서로 다른 좌표의 개수와 같아야 한다. X1, X2, ..., XN에 좌

www.acmicpc.net

stl vector에 대해서 더 공부할 수 있던 문제였다.

 

처음엔 vector<pair<int, int>> v로 선언해서 {X, 순서}를 저장하려고 했는데, 풀다보니까 순서를 굳이 저장할 필요가 없어져서 vector<int> v로 바꾸어 풀었다.

 

참고로 pair로 선언된 vector를 sort함수로 정렬할때 compare함수를 따로 작성안하면 first 값을 기준으로 정렬 된다고함!!

vector

unique 함수

unique 함수는 <algorithm>헤더에 포함되어 있으며, vector의 중복된 원소를 제거할 때 사용할 수 있는 함수이다.

ForwardIterator unique (ForwardIterator first, ForwardIterator last);

 

사용할때는 vector가 정렬된 상태여야 한다.

#include <algorithm>
#include <vector>
#include <iostream>
using namespace std;

int main(void){
    vector<int> v = {9, 5, 3, 4, 4, 3, 2, 1, 5, 5, 6};

    sort(v.begin(), v.end());
    unique(v.begin(), v.end());
    for(auto c : v){
        cout << c << ' '; 
    }   //1 2 3 4 5 6 9 5 5 6 9 출력
    
}

 

위의 결과를 보면 중복된 수는 뒤쪽에 저장되는데, unique 함수는 이 중복된 수의 시작주소를 반환한다.

erase 함수와 같이 사용하면 뒤쪽 중복된 원소들을 지울 수 있다.

 

erase 함수

erase 함수는 vector 컨테이너에 포함되며, vector의 특정 범위의 원소를 지울때 사용할 수 있다.

iterator erase (const_iterator position);	//단일 위치를 지우는데 사용
iterator erase (const_iterator first, const_iterator last);	//[first, last)를 지우는데 사용

 

unique 함수와 연계하면 다음과같이 사용가능하다.

이때의 first 인자는 v벡터에서 unique함수가 반환한 중복되는 값의 시작점이 되며, erase 함수를 이용해 v에서 중복된 값들을 삭제한다.

v.erase(unique(v.begin(), v.end()), v.end());

 

lower_bound, upper_bound함수

<algorithm> 헤더에 포함되어있다.

이진탐색에 기반하므로 오름차순으로 벡터가 정렬되어 있어야 사용할 수 있다.

ForwardIterator lower_bound (ForwardIterator first, ForwardIterator last, const T& val);
ForwardIterator upper_bound (ForwardIterator first, ForwardIterator last, const T& val);

두 함수는 조금 비슷한데,

lower_bound 함수는 val보다 작지 않은(==크거나 같은) [first, last)범위의 첫번째 요소를 가리키는 반복자를 반환한다.

upper_bound 함수는 val보다 큰 [first, last) 범위의 첫번째 요소를 가리키는 반복자를 반환한다.

 

반환되는 iterator에서 vector의 첫번재 원소를 가리키는 주소인 v.begin()을 빼면 인덱스를 만들수 있다.

만약 v 벡터의 k값의 인덱스를 찾고자 한다면,

lower_bound(v.begin(), v.end(), k) - v2.begin();

 

최종 코드

#include <bits/stdc++.h>
using namespace std;

int main(void){
    ios::sync_with_stdio(false);
    cin.tie(NULL);
    
    vector<int> v;
    int N;
    cin >> N;
    for(int i = 0; i < N; i++){
        int X;
        cin >> X;
        v.push_back(X); 
    }
    
    vector<int> v2 = v;	//벡터를 복사
    sort(v2.begin(), v2.end());	//오름차순 정렬
    v2.erase(unique(v2.begin(), v2.end()), v2.end());	//중복되는 원소 제거
    for(int i = 0; i < N; i++){
        cout << lower_bound(v2.begin(), v2.end(), v[i]) - v2.begin() << ' '; //인덱스메겨서 출력
    }

}