PS/PS Log

23.09.24. 풀었던 문제들

hyelie 2023. 9. 25. 13:23

Programmers Lv. 3 보석 쇼핑, 19분

 two-pointer를 활용하면 되는 문제. 유의할 점은 start와 end 사이에 있는 보석 개수를 세야 하는데, map으로 숫자를 세면 count에 O(보석 개수)만큼의 시간이 걸리고, multiset을 쓰면 identical한 보석 개수를 셀 수 없기 때문에 map과 set을 같이 썼다.

set<string> cur_gems;
int num;
map<string, int> cur_gem_count;

bool isContainAll(){
    return cur_gems.size() == num;
}

void insert(string gem){
    cur_gem_count[gem]++;
    cur_gems.insert(gem);
}

void erase(string gem){
    cur_gem_count[gem]--;
    if(cur_gem_count[gem] == 0) cur_gems.erase(gem);
}

vector<int> solution(vector<string> gems) {
    set<string> s;
    for(string gem : gems){
        s.insert(gem);
        cur_gem_count[gem] = 0;
    }
    num = s.size();

    int start = 0, end = 0;
    insert(gems[start]);
    vector<int> answer = {-1, 100001};
    while(start < gems.size() && end < gems.size()){
        if(start > end){
            end = start;
            continue;
        }

        if(isContainAll()){
            if(answer[1] - answer[0] + 1 > end - start + 1){
                answer[1] = end + 1;
                answer[0] = start + 1;
            }
            erase(gems[start]);
            start++;
        }
        else{
            end++;
            if(end < gems.size()) insert(gems[end]);
        }


    }


    return answer;
}

 

시간복잡도

 set/map에 insert/pop 시 O(logn)이고, two-pointer가 순회하는 데 걸리는 시간은 O(n)이므로, O(nlogn)이다.

 

 

 

Programmers Lv. 3 가장 먼 노드, 8분

 weight가 1보다 크다면 dijkstra를 써야 하지만, 모든 edge weight를 1로 두기 때문에 BFS를 쓰면 되는 문제. 뭐.. 별 것 없다.

typedef pair<int, int> pii; // .first : to, .second : dist

queue<pii> q;
vector<vector<int>> edges;

int solution(int n, vector<vector<int>> edge) {
    vector<int> visited(n+1, -1);
    edges.resize(n+1);
    for(vector<int> e : edge){
        int from = e[0], to = e[1];
        edges[from].push_back(to);
        edges[to].push_back(from);
    }

    q.push({1, 0});
    visited[1] = 0;

    int max_value = -1;
    while(!q.empty()){
        pii front = q.front(); q.pop();

        for(int next : edges[front.first]){
            if(visited[next] != -1) continue;

            visited[next] = front.second + 1;
            q.push({next, front.second + 1});
            max_value = max(max_value, visited[next]);
        }
    }

    int answer = 0;
    for(int v : visited) if(v == max_value) answer++;
    return answer;
}

 

시간복잡도

 BFS는 O(V+E)

 

 

 

Programmers Lv. 3 섬 연결하기, 7분 30초

 MST를 구성하는 문제. 예전에 포스팅도 했었다. union-find를 쓰는 kruskal과 pq를 쓰는 prim 2가지 방법이 있는데, 

typedef pair<int, int> pii;

struct cmp{
    bool operator()(pii &a, pii &b){
        if(a.second == b.second) return a.first > b.first;
        return a.second > b.second;
    }
};

priority_queue<pii, vector<pii>, cmp> pq;
vector<vector<pii>> edges;
vector<int> visited;

int solution(int n, vector<vector<int>> costs) {
    edges.resize(n);
    visited.resize(n);
    fill(visited.begin(), visited.end(), false);
    for(vector<int> cost : costs){
        int from = cost[0], to = cost[1], weight = cost[2];
        edges[from].push_back({to, weight});
        edges[to].push_back({from, weight});
    }

    // prim
    visited[0] = true;
    for(pii e : edges[0]) pq.push(e);

    int answer = 0;
    while(!pq.empty()){
        pii front = pq.top(); pq.pop();
        if(visited[front.first]) continue;

        visited[front.first] = true;
        answer += front.second;
        for(pii e : edges[front.first]) pq.push(e);
    }

    return answer;
}

 

시간복잡도

 prim의 경우 O(ElogV)이지만 이 코드는 O(ElogE)이다. 기존 prim은 set을 사용해서 visited를 판별하기 때문에 O(ElogV)이다. 반면 여기서는 모든 edge에 대해 edge를 뽑는 for문이 1번씩 수행되므로 O(E), 그리고 pq에 모든 edge가 들어가므로 O(ElogE)이다.