문제 설명
카카오 초등학교의 "니니즈 친구들"이 "라이언" 선생님과 함께 가을 소풍을 가는 중에 징검다리가 있는 개울을 만나서 건너편으로 건너려고 합니다. "라이언" 선생님은 "니니즈 친구들"이 무사히 징검다리를 건널 수 있도록 다음과 같이 규칙을 만들었습니다.
- 징검다리는 일렬로 놓여 있고 각 징검다리의 디딤돌에는 모두 숫자가 적혀 있으며 디딤돌의 숫자는 한 번 밟을 때마다 1씩 줄어듭니다.
- 디딤돌의 숫자가 0이 되면 더 이상 밟을 수 없으며 이때는 그 다음 디딤돌로 한번에 여러 칸을 건너 뛸 수 있습니다.
- 단, 다음으로 밟을 수 있는 디딤돌이 여러 개인 경우 무조건 가장 가까운 디딤돌로만 건너뛸 수 있습니다.
"니니즈 친구들"은 개울의 왼쪽에 있으며, 개울의 오른쪽 건너편에 도착해야 징검다리를 건넌 것으로 인정합니다.
"니니즈 친구들"은 한 번에 한 명씩 징검다리를 건너야 하며, 한 친구가 징검다리를 모두 건넌 후에 그 다음 친구가 건너기 시작합니다.
디딤돌에 적힌 숫자가 순서대로 담긴 배열 stones와 한 번에 건너뛸 수 있는 디딤돌의 최대 칸수 k가 매개변수로 주어질 때, 최대 몇 명까지 징검다리를 건널 수 있는지 return 하도록 solution 함수를 완성해주세요.
첫 번째 친구는 다음과 같이 징검다리를 건널 수 있습니다.
첫 번째 친구가 징검다리를 건넌 후 디딤돌에 적힌 숫자는 아래 그림과 같습니다.
두 번째 친구도 아래 그림과 같이 징검다리를 건널 수 있습니다.
두 번째 친구가 징검다리를 건넌 후 디딤돌에 적힌 숫자는 아래 그림과 같습니다.
세 번째 친구도 아래 그림과 같이 징검다리를 건널 수 있습니다.
세 번째 친구가 징검다리를 건넌 후 디딤돌에 적힌 숫자는 아래 그림과 같습니다.
네 번째 친구가 징검다리를 건너려면, 세 번째 디딤돌에서 일곱 번째 디딤돌로 네 칸을 건너뛰어야 합니다. 하지만 k = 3 이므로 건너뛸 수 없습니다.
따라서 최대 3명이 디딤돌을 모두 건널 수 있습니다.
https://school.programmers.co.kr/learn/courses/30/lessons/64062#
프로그래머스
코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.
programmers.co.kr
제한 사항
- 징검다리를 건너야 하는 니니즈 친구들의 수는 무제한 이라고 간주합니다.
- stones 배열의 크기는 1 이상 200,000 이하입니다.
- stones 배열 각 원소들의 값은 1 이상 200,000,000 이하인 자연수입니다.
- k는 1 이상 stones의 길이 이하인 자연수입니다.
풀이
이 문제는 다양한 풀이가 있다.
그중 하나는 이진탐색으로 다리를 건널 수 있는 인원을 줄여나가며 답을 찾는 것이다.
다리를 건널 수 있는지 여부를 확인하는 작업은 다음과 같다.
x명의 인원이 다리를 건넜다고 가정하면 모든 다리의 수가 x번 감소한다.
즉, 연속으로 k번 x보다 작거나 같은 부분이 존재한다면 x명은 다리를 건널 수 없는 것이다.
이를 이진탐색을 통해 가능한 인원 x명을 찾아내면 된다.
다른 방법으로는 deque를 sliding window처럼 사용하는 것이다.
우선, 다리를 앞에서부터 조회하며 현재 처리하는 다리의 index와의 차이가 k개 이상이 되는 것을 제거한다.
이전 다리들이 현재 처리하는 다리와 무관하기 때문이다.
이때, deque의 앞에서부터 제거해 나간다. (deque의 front 부분이 index차이가 많이 나기 때문)
index를 비교해야 하기 때문에 deque는 pair<int,int>의 형태를 갖게 한다.
그리고 현재 처리하는 다리의 수보다 작은 것들도 제거한다.
이전 단계에서 index의 차이를 k개로 한정했기 때문에 사이에 있는 작은 숫자들은 무시해도 되기 때문이다.
그리고 현재 다리의 수를 deque에 삽입한다.
위 과정을 완료한 뒤, deque의 front에 오는 수들 중 가장 작은 수를 채택하면 된다.
이때, 현재 처리하는 index가 k-1 이상인 경우에만 확인한다.
그렇지 않은 경우는 한 번에 뛰어넘을 수 있는 것이기 때문이다.
정리하자면, deque를 통해 k개 이하의 다리들을 확인하면서 가장 작은 첫 다리를 찾는 것이다.
전체 코드
#include <string>
#include <vector>
#include <deque>
#include <iostream>
using namespace std;
int solution(vector<int> stones, int k) {
int answer = 0;
deque<pair<int, int>> dq;
int minVal = 999'999'999;
for(int i = 0; i < stones.size(); i++)
{
int stone = stones[i];
// 현재 다리와 k개 차이 밖에 있는 다리 제거
while(!dq.empty() && dq.front().first <= i-k)
{
dq.pop_front();
}
// 기준이 되는 다리와 현재 다리 사이의 작은 수들 제거
while(!dq.empty() && dq.back().second < stone)
{
dq.pop_back();
}
// 현재 다리
dq.push_back({i, stone});
//비교
if(k-1 <= i)
{
minVal = min(minVal, dq.front().second);
}
}
answer = minVal;
return answer;
}