hyelie
hyelie
Hyeil Jeong
       
글쓰기    관리    수식입력
  • 전체보기 (495)
    • PS (283)
      • Algorithm (28)
      • PS Log (244)
      • Contest (6)
      • Tips (5)
    • Development (52)
      • Java (14)
      • Spring (23)
      • SQL (2)
      • Node.js (2)
      • Socket.io (3)
      • Study (4)
      • Utils (4)
    • DevOps (36)
      • Git (5)
      • Docker (4)
      • Kubernetes (2)
      • GCP (3)
      • Environment Set Up (8)
      • Tutorial (12)
      • Figma (2)
    • CS (74)
      • OOP (7)
      • OS (24)
      • DB (2)
      • Network (24)
      • Architecture (0)
      • Security (2)
      • Software Design (0)
      • Parallel Computing (15)
    • Project (15)
      • Project N2T (5)
      • Project ASG (0)
      • Project Meerkat (1)
      • Model Checking (7)
      • Ideas (2)
    • 내가 하고싶은 것! (34)
      • Plan (16)
      • Software Maestro (10)
      • 취준 (8)
hELLO · Designed By 정상우.
hyelie

hyelie

PS/PS Log

23.03.04. 풀었던 문제들

프로그래머스 디펜스 게임

 앞에서부터 priority queue를 써서 제일 큰 값을 줄여가면 되는 문제. 단순 구현이다.

typedef long long ll;
int solution(int n, int k, vector<int> enemy) {
    priority_queue<ll> pq;
    int i = 0;
    ll sum = 0;
    
    while(1){
        if(i < enemy.size()){
            if(n >= sum + enemy[i]){ // 이번 wave 감당 가능하면 넣음
                sum += enemy[i];
                pq.push(enemy[i]);
                i++;
            }
            else if(k > 0){ // 이번 wave 감당 불가면 무적건 써야 함. 없으면 불가
                sum += enemy[i];
                pq.push(enemy[i]);
                i++;
                k--;
                sum -= pq.top();
                pq.pop();    
            }
            else break;
        }
        else break;
    }
    
    return i;
}

 

시간복잡도

 전체 array를 순회하고, pq를 쓰므로 O(nlogn)

 

 

프로그래머스 시소 짝꿍

 상당히 귀찮은 문제. 처음에는 lower_bound로 구할려 했는데 이러면 내가 원하는 값이 있는지 없는지가 아니라 그거보다 큰 값이 나온다. 그리고 indexing도 귀찮고. 그래서 map을 쓰는 게 좋다.

  • map에 무게가 i인 사람 명수를 저장한다.
  • weights를 순회하면서 해당 몸무게를 가진 사람과 짝궁이 될 수 있는 후보군을 추린다.
    • setAbles 함수를 사용한다. 만약 % 결과가 0이라면 해당 몸무게는 존재한다(정수값이니까) 그렇지 않으면 존재하지 않음.
    • 그 후보군의 무게 명수를 answer에 더한다. 단, 후보군 무게 == 현재 탐색중인 사람 몸무게인 경우에는 그 사람을 빼야 하므로 -1을 한다.
  • answer / 2를 리턴한다.(중복되는 경우의 수가 있기 때문)
#include <string>
#include <vector>
#include <algorithm>
#include <map>
#include <iostream>

using namespace std;

map<int, int> m; // m[i] : 무게가 i인 사람 명수

// w에 해당하는 배율이 가능한 위치 찾음
typedef pair<int, int> pii;
vector<pii> positions;
vector<int> ables(7);
void setAbles(int w){
    for(int i = 0; i<positions.size(); i++){
        int left = positions[i].first * w;
        if(left % positions[i].second){
            ables[i] = -1;
        }
        else{
            ables[i] = left / positions[i].second;
        }
    }
}

long long solution(vector<int> weights) {
    positions =  {{2, 2}, {2, 3}, {2, 4}, {3, 2}, {3, 4}, {4, 2}, {4, 3}};
    for(int w : weights){
        if(m.find(w) == m.end()) m[w] = 1;
        else m[w]++;
    }
    
    long long answer = 0;
    for(int i : weights){
        setAbles(i);
        for(int a : ables){
            if(a == -1) continue;
            if(m.find(a) != m.end()){
                answer += m[a] - (a == i);
            }
        }
    }
    
    return answer/2;
}

 

시간복잡도

 map insert, search는 O(logn). for문은 O(n). O(nlogn)이다.

 

 

프로그래머스 미로 탈출

 간단한 BFS 문제. 항상 그렇듯 BFS에서 visited는 q에 넣는 순간이다. 그리고 좌표평면에서 탐색할 때는 dr[4], dc[4]를 쓰자. 편하다.

 문제는 [시작점 - 레버], [레버 - 도착점]의 최단거리를 찾는 것이다. 좌표평면에서 최단거리 탐색이기 때문에 BFS를 사용하면 된다.

int dr[4] = {1, 0, -1, 0};
int dc[4] = {0, 1, 0, -1};
bool visited[101][101];
vector<string> Maps;
int maxr, maxc;
struct Search{
    int r, c, dist = 0;  
};

void initVisited(){
    for(int r = 0; r<maxr; r++){
        for(int c = 0; c<maxc; c++){
            visited[r][c] = false;
        }
    }
}

int BFS(Search start, Search end){
    queue<Search> q;
    q.push(start);
    visited[start.r][start.c] = true;
    
    while(!q.empty()){
        Search cur = q.front(); q.pop();
        int cr = cur.r, cc = cur.c, cd = cur.dist;
        if(cr == end.r && cc == end.c) return cd;
        for(int i = 0; i<4; i++){
            int nr = cr + dr[i], nc = cc + dc[i];
            if(0 <= nr && nr < maxr && 0 <= nc && nc < maxc && !visited[nr][nc] && Maps[nr][nc] != 'X'){
                Search next; next.r = nr; next.c = nc; next.dist = cd + 1;
                visited[nr][nc] = true;
                q.push(next);
            }
        }
    }
    return -1;
}

int solution(vector<string> maps) {
    Maps = maps;
    maxr = maps.size(); maxc = maps[0].size();
    
    Search start, lever, exit;
    for(int r = 0; r < maxr; r++){
        for(int c = 0; c<maxc; c++){
            if(maps[r][c] == 'S'){
                start.r = r; start.c = c;
            }
            else if(maps[r][c] == 'E'){
                exit.r = r; exit.c = c;
            }
            else if(maps[r][c] == 'L'){
                lever.r = r; lever.c = c;
            }
        }
    }
    
    initVisited();
    int start2lever = BFS(start, lever);
    
    initVisited();
    int lever2exit = BFS(lever, exit);
    
    if(start2lever == -1 || lever2exit == -1) return -1;
    
    return start2lever + lever2exit;
}

 

시간복잡도

 BFS는 O(V + E)인데 E = 4V이므로 O(V)

 

 

Leetcode 2444. Count Subarrays With Fixed Bounds

 첫 접근은 [범위 밖에 나가는 것들을 다 빼고 생각하자] 였다. 그러나 이렇게 해도 [1, 1, 1, 1]과 같은 경우를 처리하기 힘들었다. 어찌저찌 two-pointer 같다는 생각은 했으나... 잘 모르겠어서 solution을 봤다. 처음에는 보고도 "대체 왜 이게 답임" 이 생각을 했다.

 조금 풀어서 보자. 앞에서부터 순회한다고 생각하자.

 

 일단 nums[i]가 maxK보다 크거나, nums[i]가 minK보다 작다면 i는 무조건 subarray에 속하지 않는다. 이건 문제 조건에 의해 이렇게 될 수 밖에 없다. i+1부터 subarray를 만든다고 가정하자. 이 때 index를 start라고 하자.

 

 그러면 나머지 경우는 어떨까? minK <= nums[i] <= maxK인 경우. 이 때 array는 무조건 start+1부터 시작일 것이다.

  • minK, maxK가 둘 중 하나라도 발견되지 않은 경우, subarray가 만들어지지 않으므로 더 탐색해야 한다.
  • minK, maxK가 발견되어 있는 경우
    • 새로 들어온 수(nums[i])가 minK 또는 maxK인 경우 : 이 경우 새로운 subarray를 구성할 수 있다.
      • nums[i]가 minK인 경우, 원래 maxK부터 nums[i]까지가 subarray를 구성한다.
        • start | start + 1 , ... , [lastMax, ... , i]
        • 괄호 친 부분이 꼭 들어가야 하는 subarray이고, 괄호 왼쪽부터 start + 1까지 넣을 수 있다. 연속되어야 하므로 lastMax- start이다.
      • nums[i]가 maxK인 경우, 원래 minK부터 nums[i]까지 subarray를 구성한다.
        • start | start + 1 , ... , [lastMin, ... i]
        • 괄호 친 부분이 꼭 들어가야 하는 subarray이고, 괄호 왼쪽부터 start + 1까지 넣을 수 있다. 연속되어야 하므로 lastMin- start이다.
    • 새로 들어온 수가 minK < nums[i] < maxK인 경우
      • start | start + 1 , ... , [[minK와 maxK가 있는 subarray], nums[i]]
      • 위와 같이 표현할 수 있다. 이미 minK와 maxK가 발견되어 있기 때문에 원래 subarray에 nums[i]를 포함시킨다. 이 때, min(lastMin, lastMax) - start값을 더해야 한다.
        • 예를 들어 2 1 3 5 2, minK = 1, maxK = 5라 하자.
        • 2 1 3 5가 탐색된 상황에서 2를 추가로 탐색했다. 이 때 [minK와 maxK가 있는 subarray]는 [1 3 5]이다.
        • 따라서 2 [1 3 5]로 표현할 수 있다.
        • 이 때 2를 추가로 탐색했는데, 이를 [minK와 maxK가 있는 subarray]에 포함하고 그 앞에 있는 element를 순차적으로 포함해야 한다.
        • 2 [1 3 5 2] , 그리고 [2 1 3 5 2] 이렇게.
    • 간단하게 표현할 수 있다. nums[i]가 minK인 경우 lastMin를 i로 갱신하고, nums[i]가 maxK인 경우 lastMax를 i로 갱신한다.
    • lastMin과 lastMax가 둘 다 있는 상황이라면 min(lastMin, lastMax) - start를 한다. 이는 [minK와 maxK가 있는 subarray의 제일 앞의 index] - start를 의미한다.

 

 위와 같은 pseudo code로 표현할 수 있다. 코드로 나타내면 아-주 간단하다.

// Runtime 114 ms Beats 84.8%
// Memory 70.4 MB Beats 57.55%

class Solution {
public:
    long long countSubarrays(vector<int>& nums, int minK, int maxK) {
        long long answer = 0;
        int lastMax = -1, lastMin = -1, n = nums.size(), start = -1;
        for(int i = 0; i<n; i++){
            if(nums[i] > maxK || nums[i] < minK){
                start = i;
                lastMax = -1; // not found
                lastMin = -1; // not found
            }
            else{
                if(nums[i] == minK) lastMin = i;
                if(nums[i] == maxK) lastMax = i;

                if(lastMin != -1 && lastMax != -1){
                    answer += min(lastMax, lastMin) - start;
                }
            }
        }
        return answer;
    }
};

 

 솔직히 면접에서 이거 물어보면 GG다. 좋은 경험 했다고 생각하자... i번째 index가 array에 추가되었을 때 몇 개의 추가 array가 생기는지를 고민해 보았으면 쉽게 풀렸을 것 같다. ㅠㅠ

 

 

시간복잡도

 앞에서부터 뒤로 순회만 하니 O(n)이다.

 

공간복잡도

 추가 공간을 사용하지 않으니 O(1)이다.

 

 

 

 

 

 

 

 

 

 

저작자표시 (새창열림)

'PS > PS Log' 카테고리의 다른 글

23.03.06. 풀었던 문제들  (0) 2023.03.07
23.03.05. 풀었던 문제들  (0) 2023.03.06
23.03.03. 풀었던 문제들  (0) 2023.03.03
23.03.02. 풀었던 문제들  (0) 2023.03.02
23.03.01. 풀었던 문제들  (0) 2023.03.01
    hyelie
    hyelie

    티스토리툴바