(7/2 - X)

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

 

코딩테스트 연습 - 구명보트

무인도에 갇힌 사람들을 구명보트를 이용하여 구출하려고 합니다. 구명보트는 작아서 한 번에 최대 2명씩 밖에 탈 수 없고, 무게 제한도 있습니다. 예를 들어, 사람들의 몸무게가 [70kg, 50kg, 80kg, 5

programmers.co.kr

 

 

구현

총 두 가지를 생각해 내야 하는데,

1. 어떻게 하면 최대한 적은 보트를 쓰면서 사람을 태울 수 있는가 -> 최소 몸무게와 최대 몸무게를 태운다. (Greedy)

2. 어떻게 하면 제한 시간을 초과하지 않게 적절한 자료구조 선택/코드 구상을 할 것인가. (코딩 실력..)

 

 

나는 2에서 막혔다.

처음에 짰던 코드는 sort를 한 후 최소 몸무게+최대 몸무게를 비교한 후 limit을 넘으면 그 다음으로 최대 몸무게를 다시 최소 몸무게랑 더해서 인덱스을 감소시키는 형태로 풀었다.

 

구글링을 한 후 "최소 몸무게와도 못 타면 최대 몸무게는 혼자 탈 수밖에 없다"라는 사실을 알았다.

앞뒤 pop이 가능한 deque 자료구조에 넣고, 최소와 최대를 더해서 limit을 넘는다면 바로 pop_back()을 하고 answer를 증가시키고, limit을 넘지 않는다면 pop_back, pop_front를 하는 방식으로 구현했다.

 

 

실수

시퀀셜한 자료구조는 erase나 pop을 하면 컨테이너의 부분 메모리가 아닌 전체 메모리 복사가 이루어지기 때문에 남발하게 되면 시간 초과가 일어날 수 있다. 메모리의 복사를 최소로 줄여야 한다.

 

 

코드

// 프로그래머스 고득점 kit - greedy - 구명보트
#include <string>
#include <vector>
#include <deque>
#include <algorithm>

using namespace std;

int solution(vector<int> people, int limit) {
    int answer = 0;
	deque<int> d;
	for (const auto& i : people) {
		d.push_back(i);
	}
    sort(d.begin(), d.end());
	while (!d.empty()) {
		if (*(d.begin()) + *(d.end() - 1) <= limit) {
			answer++;
			d.pop_back();
			if (d.empty()) 
				break;
			d.pop_front();
		}
		else {
			answer++;
			d.pop_back();
		}

    }
    return answer;
}
int main() {
    vector<int> v{ 70,50, 80,50 };
    solution(v, 100);
}

 

(6/28 - △) 히든 테스트 케이스들을 질문하기에서 알아내고 맞췄기 때문에

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

 

코딩테스트 연습 - 디스크 컨트롤러

하드디스크는 한 번에 하나의 작업만 수행할 수 있습니다. 디스크 컨트롤러를 구현하는 방법은 여러 가지가 있습니다. 가장 일반적인 방법은 요청이 들어온 순서대로 처리하는 것입니다. 예를

programmers.co.kr

 

구현

현재 시점(time)에 따라 총 소요 시간이 적은 작업을 먼저 시작하면 평균값이 최소로 나온다.

1. 작업들을 {key:요청 시점, value: 총 소요 시간} 해싱을 이용하여 map에 저장한다. -> 요청 시점 key는 중복될 수 있으므로 multimap을 이용한다.

2. 현재 실행하고 있는 작업이 있는가? NO-> 2.1, YES->3

2.1. 현재 시점(time)에 따라 실행 가능한 작업들이 있는가? NO-> 7 YES-> 2.1.1

2.1.1. 작업들 중 소요 시간이 적은 작업을 시작한다.

3. 작업을 수행하고 있다는 느낌으로, 작업 시간(doing_time)을 카운팅한다.  (★쉴 시간 없이, 단계 2에서 작업을 넣어주므로 단계2  다음으로 바로 time++ 하지 않고 3으로 오도록 순서를 짜자.)

4. 수행하고 있는 작업의 작업 시간이 총 소요 시간보다 같거나 큰가? NO-> 6 YES->4.1

4.1. sum에 (현재 시간 - 요청 시점)을 더한다.

5. 모든작업을 끝냈는가? NO->2 YES->8

6. doing_time++

7. time++

8. sum에 작업 수를 나눈 후 answer에 넣는다.

 

예시1

 

 

예시2

 

코드

#include <string>
#include <vector>
#include <map>

using namespace std;

int solution(vector<vector<int>> jobs) {
    int answer = 0;

    int jobs_size = jobs.size();
    multimap<int, int> wait_m; // doing 되기 기다리는 작업들
    for (const auto& v : jobs) {
        wait_m.insert({ v[0], v[1] }); // 0 요청시점, 1 소요시간
    }
    
    int time = 0, doing_time = 0;
    pair<int, int> job_doing = {-1, -1}; // first 요청시점, second 총 소요시간
    int sum = 0; 
    int donejobs_cnt = 0;
    while (true) {
        // 진행 중인 작업이 없다면
        if (job_doing.first < 0) { 
            // 현재 do 할 수 있는 작업들 중에서, 소요 시간이 가장 작은 것 찾기
            pair<int, int> min = { 0, 1e9 }; // 요청시점, second 총 소요시간
            auto u_b = wait_m.upper_bound(time);
            auto l_b = wait_m.begin();
            if (u_b != l_b) { // 작업할 수 있는게 있으면
                for (; l_b != u_b; l_b++) {
                    if (l_b->second <= min.second) {
                        min = *l_b;
                    }
                }
                job_doing = min;
            }
        }
        // 진행 중인 작업이 있다면
        if (job_doing.first >= 0) {
            if (doing_time >= job_doing.second) { // 진행이 다 끝나면
                 // wait_m에서 해당 작업을 찾고 erase
                auto u_b = wait_m.upper_bound(job_doing.first);
                auto l_b = wait_m.lower_bound(job_doing.first);
                for (; l_b != u_b; l_b++) {
                    if (l_b->second == job_doing.second) {
                        wait_m.erase(l_b);
                        break;
                    }
                }
                sum += (time - job_doing.first);
                job_doing = { -1, -1 };
                doing_time = 0;
                donejobs_cnt++;
                if (donejobs_cnt >= jobs_size) {
                    break;
                }
                if (wait_m.empty()) {
                    break;
                }
                continue;
            }
            else { // 진행
                doing_time++;
            }
        }
        time++;
    }

    answer = (sum / donejobs_cnt);

    return answer;
}
int main()
{
    vector<vector<int>> v{ {0,9}, {0,4}, {0,5}, {0,7}, {0,3} };
    solution(v);
}

 

(6/27 - O)

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

 

코딩테스트 연습 - 단어 변환

두 개의 단어 begin, target과 단어의 집합 words가 있습니다. 아래와 같은 규칙을 이용하여 begin에서 target으로 변환하는 가장 짧은 변환 과정을 찾으려고 합니다. 1. 한 번에 한 개의 알파벳만 바꿀 수

programmers.co.kr

 

 

구현

dfs 방식으로 풀었다.

 

1. begin의 각 자릿수의 알파벳을 a~z로 변환한다. (예를 들면, hit을 (a~z)it, h(a~z)t, hi(a~z)으로)

2. 변환할 때마다 words 내에 있는 단어와 일치한지 검사한다.

3. 일치하지 않으면 다시 2를 반복, 일치하면 count를 증가시킨 뒤 그 단어를 begin으로 두어 dfs를 호출하여 1,2를 반복한다.

4. begin이 target과 같으면 min_cnt = min(min_cnt, cnt)로 갱신한다. 그리고 함수를 반환한다.

 

 

코드

int visited[51];
int begin_len;
int words_size;
int min_cnt;

void dfs(string begin, string target, vector<string>& words, int& cnt) {
    if (begin == target) {
        min_cnt = min(min_cnt, cnt);
        for (int i = 0; i < words_size; i++) {
            if (words[i] == begin) {
                visited[i] = false;
            }
        }
        cnt--;
        return;
    }
    for (int i = 0; i < begin_len; i++) { // 앞 글자부터 하나씩 바꿔보기
        int convert_cnt = 0;
        char ori = begin[i];
        while (true) {
            begin[i] = 'a' + (convert_cnt++);
            if (begin[i] == ori) {
                continue;
            }
            if (begin[i] > 'z') {
                begin[i] = ori;
                break;
            }
            for (int j = 0; j < words_size; j++) {
                if (words[j] == begin && visited[j] == false) {
                    begin = words[j];
                    visited[j] = true;
                    cnt++;
                    dfs(begin, target, words, cnt);
                }
            }
        }
    }
    for (int i = 0; i < words_size; i++) { // 들어갔다 나왓으면 다시 visted false 처리
        if (words[i] == begin) {
            visited[i] = false;
            cnt--;
        }
    }
}


int solution(string begin, string target, vector<string> words) {
	int answer = 0;

	// words 안에 target이 있는지 확인
	bool isin = false;
	for (auto& i : words) {
		if (i == target) isin = true;
	}
	// 있으면
	if (isin) {
		// begin=hit
		// target=cog
		begin_len = begin.length();
		words_size = words.size();
		string b = begin;
		min_cnt = 1e9;
		int cnt = 0;
		dfs(b, target, words, cnt);
		answer = min_cnt;
	}
	// 없으면
	else {
		answer = 0;
	}
	return answer;
}

 

(같이 푼 친구는 bfs를 이용했는데 테스트케이스3에서 내 코드보다 5배 빠른 속도였다. 나처럼 일일이 변환하지 않아서 코드가 더 간결했다)

(6/27 - O)

 

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

 

코딩테스트 연습 - 다리를 지나는 트럭

트럭 여러 대가 강을 가로지르는 일차선 다리를 정해진 순으로 건너려 합니다. 모든 트럭이 다리를 건너려면 최소 몇 초가 걸리는지 알아내야 합니다. 다리에는 트럭이 최대 bridge_length대 올라갈

programmers.co.kr

 

구현

queue 두 개를 이용하여 다리 위에 있는 트럭, 다리에 들어가기 위해 대기 중인 트럭을 각각 담는다.

while 반복문을 이용하여 timer처럼 사용한다.

각 시간마다 나가야 할 트럭들을 pop하고, 다리 위의 무게를 고려하여 대기 중인 트럭 중 맨앞의 트럭을 push 한다.

다리 위에 있는 트럭이 비어 있을 때 반복문을 탈출한다.

 

코드

#include <string>
#include <vector>
#include <queue>

using namespace std;

int solution(int bridge_length, int weight, vector<int> truck_weights) {
    int answer = 0;

    queue<int> trucks;
    for (const int& i : truck_weights) {
        trucks.push(i);
    }

    vector<int> on_time;
    int time = 0, bridge_weight = 0;
    queue<int> onbridge;
    while (true) {
        // 이제 막 다리를 지난 트럭이 있는가?
        if (!onbridge.empty() && on_time[0] >= bridge_length) {
            bridge_weight -= onbridge.front();
            onbridge.pop();
            on_time.erase(on_time.begin());
        }

        // 트럭 한개가 다리에 진입할 수 있는가?
        if (!trucks.empty()) {
            int f = trucks.front();
            if (bridge_weight + f <= weight) {
                bridge_weight += f; // 여유 있으므로 진입!
                onbridge.push(f);
                on_time.push_back(0);
                trucks.pop();
            }
        }
        // 각 트럭들이 다리에 있던 시간 증가시켜줌
        for (auto& i : on_time) {
            i++;
        }
        time++;
        if (onbridge.empty()) break;
    }
    answer = time;
    return answer;
}

 

 

더 효율적인 코드

(속도 측면에서 내 코드와 10배나 차이났다)

#include <iostream>
#include<algorithm>
#include <functional>         // greater 사용 위해 필요  
#include <vector>
#include<queue>
using namespace std;

int solution(int bridge_length, int weight, vector<int> truck_weights) {
    int answer = 0;
    int count = 0;
    int Time = 0;
    int Truck_weight = 0;
    queue<pair<int, int>> truck_move;

    while (true)
    {
        if (weight >= Truck_weight + truck_weights.at(count))
        {
            truck_move.push(make_pair(truck_weights.at(count), bridge_length + 1 + Time));
            Truck_weight += truck_weights.at(count);
            count++;
        }

        if (count >= truck_weights.size())
        {
            answer = truck_move.back().second;
            break;
        }
        else
        {
            Time++;
            if (truck_move.front().second == Time + 1)
            {
                Truck_weight -= truck_move.front().first;
                truck_move.pop();
            }
        }

    }

    return answer;
}

(6/26 - O)

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

 

코딩테스트 연습 - 정수 삼각형

[[7], [3, 8], [8, 1, 0], [2, 7, 4, 4], [4, 5, 2, 6, 5]] 30

programmers.co.kr

 

생각보다 쉽게 풀려서 정말 기뻤던 문제!

 

 

구현

dp테이블을 이용하여 좌표마다 가질 수 있는 최댓값을 위에서 아래로 내려가면서 갱신해 준다. 가장 마지막 줄의 원소 값들 중 가장 큰 값을 리턴한다.

 

 

 

코드

#include <string>
#include <vector>
#include <algorithm>

using namespace std;

int dp[501][501];

int solution(vector<vector<int>> triangle) {
    int answer = 0;

    for (int i = 0; i < 501; i++) {
        fill(dp[i], dp[i] + 501, -1);
    }

    dp[0][0] = triangle[0][0];

    int i_size = triangle.size();
    for (int i = 1; i < i_size; i++) {
        int j_size = triangle[i].size();
        for (int j = 0; j < j_size; j++) {
            if(j - 1 >= 0)
                dp[i][j] = max(dp[i][j], dp[i - 1][j - 1] + triangle[i][j]);
            dp[i][j] = max(dp[i][j], dp[i - 1][j] + triangle[i][j]);
        }
    }
    
    answer = *max_element(dp[i_size - 1], dp[i_size - 1] + triangle[i_size - 1].size());

    return answer;
}

int main()
{
    vector<vector<int>> v;
    v.push_back({ 7 });
    v.push_back({ 3,8 });
    v.push_back({ 8,1,0 });
    v.push_back({ 2,7,4,4 });
    v.push_back({ 4,5,2,6,5 });

    solution(v);
}

 

(6/24 - O)

 

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

 

코딩테스트 연습 - 네트워크

네트워크란 컴퓨터 상호 간에 정보를 교환할 수 있도록 연결된 형태를 의미합니다. 예를 들어, 컴퓨터 A와 컴퓨터 B가 직접적으로 연결되어있고, 컴퓨터 B와 컴퓨터 C가 직접적으로 연결되어 있

programmers.co.kr

이런 테스트케이스에서 막히고, 또 저런 테스트케이스에서 막혀서 푸는 데 너무 오래 걸린 문제.. dfs/bfs의 다양한 문제들을 풀어 보지 않아서 그런가 보다. 응용을 빠르게 하지 못 하는 것 같다.

 

구현

방문하지 않은 모든 노드를 방문한다. 방문 처리를 하고, 해당 노드와 이어진 노드를 방문한다.

 

코드

// 프로그래머스 고득점 kit - 네트워크
// 6/24 - O

#include <string>
#include <vector>

using namespace std;
bool visited[201];
int answer = 0;
void dfs(vector<vector<int>>& v, int size, int start, int& cnt){
    if (start >= size) return;
    if (visited[start] == true) return;
    visited[start] = true;
    for (int i = 0; i < size; i++) {
        if (v[start][i] == 1) {
            dfs(v, size, i, cnt);
        }
    }
    cnt++;
}

int solution(int n, vector<vector<int>> computers) {
    int answer = 0;

    for (int i = 0; i < n; i++) {
        int cnt = 0;
        dfs(computers, n, i, cnt);
        if (cnt > 0) {
            answer++;
        }
    }

    return answer;
}

int main() {
    vector<vector<int>> v;

    //v.push_back({ 1,0, 0, 1 });
    //v.push_back({ 0, 1, 1, 0 });
    //v.push_back({ 0, 1, 1, 0 });
    //v.push_back({ 1,1, 0, 1 });

    //v.push_back({ 1,0, 0 });
    //v.push_back({ 0, 1, 0 });
    //v.push_back({ 0, 0, 1 });

    v.push_back({ 1, 1, 0 });
    v.push_back({ 1, 1, 0 });
    v.push_back({ 0, 0, 1 });


    //v.push_back({ 1, 1, 0 });
    //v.push_back({ 1, 1, 1 });
    //v.push_back({ 0, 1, 1 });

    //v.push_back({ 1, 0, 1, 1, 0, 0 });
    //v.push_back({ 0, 1, 0, 0, 1, 1 });
    //v.push_back({ 1, 0, 1, 1, 1, 1 });
    //v.push_back({ 1, 0, 1, 1, 1, 1 });
    //v.push_back({ 0, 1, 1, 1, 1, 1 });
    //v.push_back({ 0, 1, 1, 1, 1, 1 });

    solution(3, v);
}

 

 

 

 

 

 

(6/24 - X)

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

 

코딩테스트 연습 - 큰 수 만들기

 

programmers.co.kr

 

 

처음에는 min_element를 이용해서 푸는 방법을 떠올렸는데 3번 테스트 케이스에서 적용되지 않는 식이었다. 다음으로는 실제 값에다 자릿수의 값으로 보정 값을 줄까 생각해 봤는데 이 또한 틀린 풀이였다. 해결 방법 자체가 떠오르지 않았다. 그래서 계속 고민하다가 구글링 해서 힌트를 얻었다. 테스트 케이스마다 신경 써 줘야 할 것이 많아서 까다로웠다.

 

구현

스택을 이용한다.

 

0. numbers를 순회하면서 1-2를 반복한다.

1. 스택이 비어 있지 않고, k가 0보다 크며, c - '0'가 스택의 top보다 클 경우 이 조건을 하나라도 만족하지 않을 때까지 1.1와 1.2 반복

1.1 top을 pop 한다.

1.2 k를 1 감소시킨다.

2. c를 스택에 push 한다.

3. 스택 사이즈가 number.size() - k보다 클 때, top과 top-1의 수를 비교하며 더 큰 수를 top에 넣는다.

 

 

 

참고

케이스 중 "654321" k=1, "654321" k=5, "999" k=2를 테스트 해 보자.

 

코드

#include <string>
#include <vector>
#include <stack>

using namespace std;

string solution(string number, int k) {
    string answer = "";

    int len = number.length();
    int answer_size = len - k;

    stack<int> s;
    for (auto& c : number) { // 0
        while (!s.empty() && k > 0 && c - '0' > s.top()) { // 1
            s.pop(); // 1.1
            k--; // 1.2
        }
        s.push(c - '0'); // 2
    }
    if (s.size() > answer_size) { // 3
        int top = s.top();
        s.pop();
        if (s.top() < top) {
            s.pop();
            s.push(top);
        }
    }

    answer.resize(answer_size);
    for (int i = answer_size - 1; i >= 0; i--) {
        answer[i] = (s.top() + '0');
        s.pop();
    }

    return answer;

}

 

 

 

 

(6/23 - 세모)

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

 

코딩테스트 연습 - 위장

 

programmers.co.kr

 

 

처음에 set과 재귀를 이용해서 순서가 없는 조합을 구하며 풀었는데, 계속 시간 초과가 떴다. 모든 경우의 수를 재귀로 다 따지고 들어가서 구하니까 시간 초과가 떠 버리지.. 알고 보니 해법이 엄청 간단했다.

 

구현

안경인 안A, 안B가 있고, 모자 모A, 모B, 모C가 있다고 치자. 이때 나올 수 있는 경우의 수는 3 * 4이다.

아무것도 안 입은 경우, 안A, 안A모A, 안A모B, 안A모C, 안B, 안B모A, 안B모B, 안B모C, 모A, 모B, 모C. 이렇게. 쉽게 말하면 해당 종류의 옷을 안 입는 경우도 같이 세어 주면 된다. 문제 조건 중에 아무것도 안 입는 경우는 없다고 했으니 -1 해 주면 된다.

해싱이 가능한 map을 이용해서 m[안경]=안A, 이런 식으로 저장한다.

 

 

코드

// 프로그래머스 고득점 Kit - 위장
#include <string>
#include <vector>
#include <map>
using namespace std;

map<string, string> m;
map<string, int> cnt;
int solution(vector<vector<string>> clothes) {
    int answer = 1;

    // 0:name 1:type
    for (auto& i : clothes) {
        m.insert({ i[0], i[1] });
        cnt.insert({ i[1], 1 });
    }

    for (auto& i : m) {
        cnt[i.second]++;
    }


    for (auto& i : cnt) {
        answer *= i.second;
    }

    answer--;
    return answer;
}

int main() {
    vector<vector<string>> c(3);
    //c[0].push_back("yellowhat");
    //c[0].push_back("headgear");
    //c[1].push_back("bluesunglasses");
    //c[1].push_back("eyewear");
    //c[2].push_back("green_turban");
    //c[2].push_back("headgear");

    c[0].push_back("aa");
    c[0].push_back("A");
    c[1].push_back("bb");
    c[1].push_back("B");
    c[2].push_back("cc");
    c[2].push_back("C");

    //c[0].push_back("yellowhat");
    //c[0].push_back("headgear");
    //c[1].push_back("bluehat");
    //c[1].push_back("headgear");
    //c[2].push_back("green_turban");
    //c[2].push_back("headgear");

    solution(c);
}

 

 

+ Recent posts