문제 링크 

 

리뷰 

항상 가장 작은 수와, 그 다음 작은 수가 필요해서 자동으로 정렬해주는 우선순위 큐를 이용했다. 

우선순위 큐에서 front()를 first로 받고, pop()후에 front()를 second로 받으면 쉽게 접근할 수 있다. 

항상 2개를 꺼내니까 pop()을 2번 해줘야하는 것을 유의하자. 

 

전부 스코빌지수가 K가 됬는지는 큐의 크기가 1이 됬을 때 검사한다. 

마지막 남은 원소가 K 미만이라면 answer 는 실패다. 

 

 

 

맞았습니다 코드 

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

int solution(vector<int> scoville, int K) {
  int answer = 0;
  bool result = true;

  priority_queue<int, vector<int>, greater<int>> pq;

  for(auto s : scoville){ pq.push(s); }

  while(!pq.empty()){

    if(pq.top() > K) break; // 더 검사하지 않아도 된다
    if(pq.size() == 1 && pq.top() < K) { result = false; break; } // 실패

    int first = pq.top();
    pq.pop();
    int second = pq.top();
    pq.pop();

    pq.push(first + (second * 2));
    // cout << "first: " << first << " second:" << second << ' ';
    answer++;
  }
  if(!result) answer = -1;
  return answer;
}

int main(void) {
  ios::sync_with_stdio(0);
  cin.tie(0);

  int k = 7;
  vector<int> scofille = {1, 2, 3, 9, 10, 12};
  cout << solution(scofille, k);

  return 0;
}
728x90

문제 링크 

 

문제 유의 사항

반드시 모든 티켓을 사용해야 한다. 

반드시 시작 공항은 ICN 이다. 

모든 티켓을 사용할 수 있는 입력만 주어진다. 

가능한 경로가 여러개 나와도, 알파벳순으로 우선하는 경로를 선택한다. (== 탐색 전 정렬 필요) 

 

리뷰 

DFS 구현 시, 탐색 함수 매개변수와 종료 조건이 중요하다. 

 

탐색 목표 : 목적지, 몇번째 방문인지. 

탐색 종료 조건 : 티켓 개수가 방문 순서와 똑같으면 모든 티켓을 사용한 것이니까 종료. 

 

탐색 가능 조건 : 목적지를 시작점으로 하는 티켓이 있는지 확인 && 미방문인지 확인 

 

1) 모든 티켓을 검사. 

탐색 가능 조건이 있다면, 방문 표시하고 답 벡터에 넣는다. DFS 탐색 시작. 

DFS탐색은 true/ false 를 리턴한다.

탐색 해보고 만약 실패라면, 다시 미방문 표시 

 

2) 탐색 가능 조건이 없다면, 답 벡터에서 빼고 false 리턴. 

 

맞았습니다 코드 

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

vector<string> routes; // 정답 경로 벡터
bool visit[100002]; // 방문 체크

bool DFS(string start, int cnt, vector<vector<string>> &tickets){

  if(cnt == tickets.size()) return true; // 탐색 끝나면 true

  for(int i = 0; i < tickets.size(); i++){ // 시작점 타겟이 있는지 확인 
    if(visit[i] == false && start == tickets[i][0]){ // 미방문이고, 시작점 타겟이 맞으면, 방문!
      visit[i] = true;
      routes.push_back(tickets[i][1]); // 방문한 도착지를 답 벡터에 푸시
      bool res = DFS(tickets[i][1], cnt+1, tickets);
      if(res) return true;
      visit[i] = false;
    }
  }
  
  routes.pop_back(); // 갈 곳이 없으면, 가장 최근 도착지를 벡터에서 제거 
  return false;
}

vector<string> solution(vector<vector<string>> tickets) {

  sort(tickets.begin(), tickets.end()); // 알파벳 순 앞서는 경로 선택
  routes.push_back("ICN"); // 항상 시작은 ICN
  DFS("ICN", 0, tickets);  //시작점이 "ICN"인 티켓을 탐색

  return routes;
}
728x90

문제 링크 

 

 

첫 번째 풀이 : 시작점을 기준으로 정렬했다.

end_point는 차가 나가는 지점을 저장한다. 

answer 는 감시카메라 개수 변수다. 

 

차 2대가 {1, 3} {4, 5} 이 순서로 오는 경우

두 차는 겹치지 않으니까 answer++ 로 카메라를 추가해줘야 한다. 

그리고 마지막 차가 나가는 지점은 5가 된다. end_point = r[1];

 

차 2대가 {1, 6} { 2, 3} 이 순서로 오는 경우

두 번째 차가 빨리 나가버린다. 

이 때는 종료지점이 더 짧은 3으로 end_point를 갱신해줘야 한다. 

 

차 2대가 {1, 6} { 2, 3} {4, 9} 이 순서로 오는 경우

 {1, 6} { 2, 3} 을 감시하는 카메라 말고, 하나 더 필요하다. 

새로운 차 { 4, 9 }를 감시하려면,  이미 감시한 {1, 6} 이 아니라, {2, 3}과 {4, 9}가 겹치는지를 확인해야 한다. 

#include <string>
#include <vector>
#include <algorithm>
using namespace std;
int solution(vector<vector<int>> routes) {
  int answer = 1; // 차가 1대 이상이니까 카메라는 최소 개수 1
  int end_point = routes[0][1]; // 현재 차가 나가는 지점

  sort(routes.begin(), routes.end());
  for(auto r : routes){ // end_point: 현재 차,  r: 다음 차
    if(end_point < r[0]){ // 현재 차와 다음 차가 겹치지 않으면, 카메라 추가
      answer++;
      end_point = r[1]; // 다음 차 나가는 지점으로 갱신
    }

    // 현재 차가 end_point 보다 먼저 나간다면? 나가는 지점을 현재 차로 수정  
    if(r[1] <= end_point) end_point = r[1];
  }
  return answer;
}

 

 

두 번째 풀이 : 종료 지점으로 정렬했다. 

 

여기서는 감시카메라 개수를 0 으로 초기화 한다. 

마지막 지점은  end_point = -30001 ; 가장 작은 수로 초기화 한다. 

따라서 자동차가 1개 여도, 감시카메라 개수를 1 추가한다. 

 

주어진 배열

[[-20,-15], [-14,-5], [-18,-13], [-5,-3]]

종료 지점이 빠른 순으로 정렬하면 아래와 같다. 

[[-20,-15], [-18,-13], [-14,-5],  [-5,-3]]

 

자동차 1개일 때는 첫 번째 자동차만 감시하면 된다.

여기서 감시카메라 개수는 1이다. 이때 end_point = -15 

 

두 번째 자동차 시작점은 -18이다.  end_point 보다 작다. 따라서 감시카메라를 추가하지 않아도 된다. 

 

세 번째 자동차의 시작점은 -14 니까 end_point 보다 크다. 감시카메라를 추가해야한다. 

이 때 end_point는 세 번째 자동차의 종료지점으로 갱신한다. 

end_point 는 자동차가 겹치는 마지막 지점으로 이해하면 수월하다. 

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

bool cmp(vector<int> &a, vector<int> &b) {
  return a[1] < b[1]; // 종료 지점 기준으로 정렬
}

int solution(vector<vector<int>> routes) {
  int answer = 0;
  sort(routes.begin(), routes.end(), cmp);
  int end_point = -30001; // 초기값은 가장 작은 수

  for(auto r : routes){ // end_point: 현재 차,  r: 다음 차
    if(end_point < r[0]){
      answer++;
      end_point = r[1];
    }
  }
  return answer;
}

 

 

728x90

문제 링크 

 

DFS를 풀 때 매개변수를 줄면 코드 짜는 나도 덜 헷갈리고 메모리도 덜 소모한다. 

탐색할 때 불변하는 값은 전역변수로 해두었다. (컴퓨터 총 개수)

 

맞았습니다 코드 

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

bool checked[202]; // 방문 체크 배열
int node_cnt; // 컴퓨터 총 개수

void dfs(int current, vector<vector<int>> &computers){
  checked[current] = true;

  for(int i = 0; i < node_cnt; i++){
    if(!checked[i] && computers[current][i] == 1) // 미방문이고 서로 연결됬다면 탐색하자 
      dfs(i, computers);
  }
}

int solution(int n, vector<vector<int>> computers) {
  int answer = 0;
  node_cnt = n; // 컴퓨터 개수를 전역변수로 만든다

  for(int i = 0; i < n; i++){ // 모든 노드에서 탐색 시작
    if(!checked[i]){ // 미방문이라면 탐색 시작
      answer++;
      dfs(i, computers);
    }
  }
  return answer;
}
728x90

문제 링크 

 

저번에 BFS로 푼 것을 DFS로 다시 풀어봤다.

DFS는 재귀함수의 매개변수를 뭐로 할지와 종료조건이 중요하다. 

 

문제 설명에 '최소'라는 단어가 나오면 BFS 또는 이분탐색으로 풀 수 있는 가능성이 있다. 

DFS로 이 문제를 풀 땐 아무래도 단어목록을 매개변수로 넘겨야 하다보니 BFS가 더 직관적이었다. 

 

 

DFS로 푼 코드 

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

string tg; // 목표
int answer = 50;  // 최소 횟수 저장
bool checked[52]; // 단어 확인 여부

bool diff_one(string cur, string w){// 단어 cur와 w를 비교 
  int diff_cnt = 0;
  for(int i = 0; i < w.size(); i++){
    if(cur[i] != w[i]) diff_cnt++;
  }
  return (diff_cnt == 1); // 1글자만 다른 단어라면 true 
}

void dfs(string s, vector<string> words, int cnt){

  if(answer <= cnt) return; // 백트래킹 
  if(s == tg) { 
    answer = min(cnt, answer); // 타겟 찾았다면 최소 횟수를 갱신하고 종료
    return;
  }

  int w_len = words.size();
  for(int i = 0; i < w_len; i++){
  
    if(diff_one(s, words[i]) && !checked[i]){ // 1글자만 다르고, 확인 안해본 단어라면 
      checked[i] = true;
      dfs(words[i], words, cnt + 1);
      checked[i] = false;
    }
  }
}

int solution(string begin, string target, vector<string> words) {

  tg = target; // 시작단어와 타겟단어 전역변수
  dfs(begin, words, 0); // begin 단어부터 탐색 시작 
  if(answer == 50) answer = 0; // 타겟 못찾음
  return answer;
}
728x90

출처: 프로그래머스

 

수강신청 이유  

알고리즘 코딩 테스트 준비를 혼자하는게 벅차고 지지부진해져서. 함께 문제 푸는 커뮤러닝 수강신청을 해봤다. 

C++ STL 이 편해서 C++ 반을 선택했다.  (종류는 C++, JAVA, Python이 있었다. )

 

1달간 출첵 및 문제풀기, 다른 사람 코드에 댓글 달기, 중간고사 기말고사를 치게된다. 

수강료는 30만원 인데, 국비지원카드로 10%인 3만원을 결제하면 된다. 수료 기준을 충족하면 3만원을 환급받을 수 있다. 

 

프로그래머스 커뮤러닝의 목적 

1개의 문제를 여러 풀이 방법을 공부하는것이 취지. 다른 사람의 코드를 읽는 훈련도 된다. 

 

4주 커리큘럼

1주일에 3~4문제를 풀기 때문에 문제 양이 많지는 않다. 

하지만 리뷰를 하면서 다른 사람 코드를 찬찬히 읽게 되고 몰랐던 문법도 알게된다. 수강생들의 질문 답변이 활발히 이루어져서 좋았다. 

 

문제 풀기 관련 유의사항

테스트가 주어진 시간보다 빨리 마친다면? 
문제를 다 풀어도 ‘ 테스트 종료’ 누르지 말기!  ‘제출 후 채점하기’ 버튼만 누르기. 브라우저는 꺼도 됨. 
테스트는 딱 1번만 진행됨. 재응시 불가.

반드시 내가 신청한 코스의 언어로 풀기. 코드 제출이 완료되면 내 코드가 바로 질문게시판에 올라가게 된다.


영상강의 기간 내에 열람하기. 코딩테스트 기간 이후에 영상강의 시청 기간이 따로 있음
코딩테스트 기간 내에 제출완료 하기. 기한 엄수! 재응시 불가. 

 

피어 코드 리뷰

코드리뷰 기간에 질문게시판에 올라온 다른 사람 코드에 한 문제당, ‘5개 이상 답변’을 작성해야 한다!

잘 모르는 문제더라도, 반드시 리뷰 남기기! 

 

프로그래머스 스쿨 접속 유의사항 

HRD 가입 메일과 프로그래머스 가입메일이 동일해야 ‘프로그래머스 스쿨’에 초대 받을 수 있다. 
학습 페이지 접근이 안된다면, 프로그래머스에 “HRD 가입 메일”로 새로 가입하기! 

 

문제 관련 질문 

학습 과정에는 어떤 문제를 풀까?

프로그래머스 고득점 키트 문제들
커뮤러닝에서 푸는 문제의 레벨은? 

1, 3주차 학습은 레벨 2정도에 가까움. 3시간에 2문제 푸는데 고득점 키트 문제 보다 난이도 높은 편. 레벨 3정도. 

중간고사, 기말고사 문제는 유출 하면 법적책임 물어야 함. 문제 맞추는 것과 수료 여부는 관계가 없음. 


[중요] 자부담 환불 관련 공지

OT 진행일 (3월 22일 화요일) 부터는 자부담환불 불가. 

‘수료증 발급’은 채널톡으로 별도 문의하기. 이후 KDT교차 참여 가능.
(‘수료증 발급’이 필수가 아니므로 별도 문의해야 발급 가능. 수료증이 취업에 도움되는 것은 아님)

과정 종료 후, HRD-net 만족도 조사 필수.  HRD-net 수강평 입력 필수. 
HRD-net 마이 페이지에 이메일 누락되어 있으면, 반드시 프로그래머스에 가입되어 있는 이메일 주소로 채워놓기. 

 

 

로그인 시(수강 시) 1일 1회 “본인인증 얼굴캡쳐” 필수.

수강 시, 매일 카메라를 켜서 본인 사진 찍고 제출해야 ‘본인인증’받을 수 있음

본인인증 캡쳐 안찍으면 훈련인정 불가.
부정수급 방지를 위해 동시 다중기기 접속 불가. (IP중복 접속 금지) 기기 변경할 때 ‘로그아웃’ 습관 들이기. 

1일 8시간 이상 ‘초과’했을 경우 훈련인정 불가. 
**하루에 8시간 초과하지 않도록 주의. 반드시 자신의 진도율 확인하기.** 
수강시 시스템에서 ‘완강’처리가 떠야 훈련인정 가능. 

커뮤러닝 재수강 시 자비부담 해야함.  커뮤러닝을 재수강하기 보다는 심화과정인 K디지털 트레이닝 참여를 권함. 

종강일 전날, 만족도 조사 및 환급 신청 일정 공지 해주니까 기다리기. 
훈련기관(프로그래머스) 외에도 여러 기관의 교육 종료일 부터 1달 후에 환급 절차가 시작됨

질문이 있다면, 스쿨 페이지에 남기기.  스쿨 페이지가 닫힌다면 채널톡으로 질문 남기기.

 


[4주 수강 완료! ] 

4주가 길 것 같았는데, 커리큘럼에 따라서 문제 풀고.. 다른 분들 코드 읽으면서 서로 피드백 주고받다 보니까 시간이 훅갔다. 

정말.. 금방이다. 

 

1주차, 3주차: 문제풀이 연습 

프로그래머스 고득점 키트에 공개되어 있는 문제들을 푼다. 

다른 점이 있다면, 문제마다 제한 시간을 2시간? 3시간 정도를 두고 타이머가 흘러간다. (멈출 수 없다!)

 

커뮤러닝에서는 문제 마다 제한시간을 충분하게 주지만, 실제 기업 코테에서는 한 문제당 20분~50분 이내로 풀어야 한다.

타이머가 흘러가는 환경에 익숙해질 필요가 있는데, 커뮤러닝을 통해 요런 부분에서 도움을 받았다. 굳굳.

 

내가 푼 코드는 '질문하기' 게시판에 자동으로 제출된다. 

문제푸는 기간이 끝나면 '질문하기' 게시판에서 모두의 코드를 볼 수 있다. 

내가 짠 코드가 아닌 이상 읽기가 쉬운건 아니다. 하지만 시간이 지나면 훈련이 되서 점점 익숙해진다. 

 

좋았던 점 -> 함께 알고리즘 풀이를 꾸준히 해나가고 있다는 느낌 덕에 덜 지치며 문제를 풀 수 있었다. 

 

2주차, 4주차 : 중간 기말고사

프로그래머스 개발자분들이 직접 만든 (레벨 3~4) 기업 코테 수준의 문제 2개를 3시간 안에 푸는 것이다. 

이건 저작권이 있기 때문에 문제를 온라인에 공유해서도 안되고, 해설 코드나 풀이도 제공되지 않는다. 

못 푼 문제도 있었지만, 다른 분들 코드를 보며 내 코드의 보완점을 얻어갈 수 있는 시간이어서 매우 만족했다. 

그리고 프로그래머스 매니저분들께서 모든 부분에서 친절하게 답변해주셔서 코스 진행하는 내내 감사했다. 

728x90

문제 링크 

 

 

리뷰 

문자열 길이가 100만 이하다. 그래서 효율성을 고려해야한다. 

그리고 자연수라는 조건이 있다. 자연수는 0 포함임을 유의하자! 

 

맞았습니다 코드

#include <iostream>
#include<string>
#include<stack>
using namespace std;

int solution(string s){
  int answer = 0;
  int len = s.length();
  int i = 0;
  stack<char> st;

  if(s.empty() || len % 2 == 1) return 0;
  while(i < len){
    if(st.empty() || st.top() != s[i]) {
      st.push(s[i]);
    }
    else if(st.top() == s[i]) {
      st.pop();
    }
    i++;
  }
  answer = (st.size() != 0) ? 0 : 1;
  return answer;
}
728x90

문제 링크 

 

 

맞았습니다 코드 

 

#include <string>
#include <vector>
#include <queue>
using namespace std;

bool check[51]; // 확인 여부 

int solution(string begin, string target, vector<string> words) {
  int min_cnt = 1e9; // 최소 이동 횟수 
  int vector_size = words.size();
  int word_size = begin.size();

  queue<pair<int,string>> qu;
  qu.push({0, begin});

  while(!qu.empty()){
    int cnt = qu.front().first;
    string current_s = qu.front().second; // 비교 문자열
    qu.pop();

    for(int i = 0; i < vector_size; i++){
      // 이미 확인한 문자 지나감
      if(check[i]) continue;

      // 현재 문자열과 i번째 문자열이 1개만 다른지 확인
      int diff_cnt = 0;
      for(int d = 0; d < word_size; d++){
        if(words[i][d] != current_s[d]) diff_cnt++;
      }

      if(diff_cnt == 1){
        if(words[i] == target) { min_cnt = cnt + 1; break; } // 찾음
    
        qu.push({cnt+1, words[i]}); // 1개만 다르니까 여기로 이동 
        check[i] = true; // 이동했으니까 표시 
      }
    }
  }
  if(min_cnt == 1e9) min_cnt = 0;
  return min_cnt;
}
728x90

문제 링크 

 

숫자를 제거했을 때, 맨 앞에 0이 위치하면 안된다. 

 

 

맞았습니다 코드 

#include <string>
#include <vector>
using namespace std;


string solution(string number, int k) {
    string answer = "";
    int len = number.length() - k; // 첫 번째 숫자로서 가능한 인덱스 
    int start_idx = 0; // 비교를 시작할 인덱스 

    for (int i = 0; i < len; i++) {

        char max_num = number[start_idx];
        int max_idx = start_idx;

        for (int j = start_idx ; j <= k+i; j++) {
            if (max_num < number[j]) {
                max_num = number[j];
                max_idx = j;
            }
        }
        start_idx = max_idx + 1;
        answer += max_num;
    }
    return answer;
}
728x90

문제 링크 

 

 

맞았습니다 코드 

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

bool cmp(vector<int> &a, vector<int> &b){
  return a[2] < b[2];
}
int get_parent(vector<int> &parent, int x){
  // 부모노드가 자신이라면 자신을 리턴
  if(parent[x] == x) return x;
  // 부모노드가 자신이 아니라면, 최상위 부모 찾기
  return parent[x] = get_parent(parent, parent[x]);
}

void union_parent(vector<int> &parent, int a, int b){
  a = get_parent(parent, a);
  b = get_parent(parent, b);
  // 작은 노드쪽의 부모로 병합
  a < b ? parent[b] = a : parent[a] = b;
}
bool find(vector<int> &parent, int a, int b){
  a = get_parent(parent, a);
  b = get_parent(parent, b);
  return a == b; // 비교 내용을 리턴, 사이클 방지용
}
// 크루스칼 알고리즘 : 비용이 적은 순으로 costs 정렬
int solution(int n, vector<vector<int>> costs) {
  int answer = 0, maxNum = 0;

  sort(costs.begin(), costs.end(), cmp);
  for(auto c : costs) if(maxNum < c[1]) maxNum = c[1];

  vector<int> parent; // i번째 노드의 부모노드를 저장하는 parent 벡터
  for(int i = 0; i <= maxNum; i++) parent.push_back(i);

  for(auto c : costs){
    // 두 개의 부모 노드가 다르다면 (사이클 없다면)
    if(!find(parent, c[0], c[1])){
      answer += c[2]; // 결과에 가중치 추가
      union_parent(parent, c[0], c[1]); // 부모노드 병합
    }
  }
  return answer;
}

int main(void) {
  ios::sync_with_stdio(0);
  cin.tie(0);

  int n = 4;
  vector<vector<int>> costs{{0,1,1}, {0,2,2}, {1,2,5}, {1,3,1}, {2,3,8}};
  cout << solution(n, costs);

  return 0;
}
728x90

+ Recent posts