코딩 테스트/백준

[BaekJoon/백준] 17298번: 오큰수(C/C++)

JongHoon 2021. 12. 29. 21:31

백준 17298번: 오큰수

https://www.acmicpc.net/problem/17298

 

17298번: 오큰수

첫째 줄에 수열 A의 크기 N (1 ≤ N ≤ 1,000,000)이 주어진다. 둘째 줄에 수열 A의 원소 A1, A2, ..., AN (1 ≤ Ai ≤ 1,000,000)이 주어진다.

www.acmicpc.net


문제 설명

크기가 N인 수열 A = A1, A2, ..., AN이 있다. 수열의 각 원소 Ai에 대해서 오큰수 NGE(i)를 구하려고 한다. Ai의 오큰수는 오른쪽에 있으면서 Ai보다 큰 수 중에서 가장 왼쪽에 있는 수를 의미한다. 그러한 수가 없는 경우에 오큰수는 -1이다.

예를 들어, A = [3, 5, 2, 7]인 경우 NGE(1) = 5, NGE(2) = 7, NGE(3) = 7, NGE(4) = -1이다. A = [9, 5, 4, 8]인 경우에는 NGE(1) = -1, NGE(2) = 8, NGE(3) = 8, NGE(4) = -1이다.


입력과 출력

  • 입력: 첫째 줄에 수열 A의 크기 N (1 ≤ N ≤ 1,000,000)이 주어진다. 둘째 줄에 수열 A의 원소 A1, A2, ..., AN (1 ≤ Ai ≤ 1,000,000)이 주어진다.
  • 출력: 총 N개의 수 NGE(1), NGE(2), ..., NGE(N)을 공백으로 구분해 출력한다.


접근 방법

이번 문제는 지문을 대충 읽어 조금 헷갈렸었다. 오른쪽 큰 수 중에서 가장 큰 수를 뽑는게 아니라, 오른쪽 큰 수 중 가장 왼쪽에 있는 수를 뽑는 것이다. 그래서 예제 1번의 3 5 2 7이 출력 결과가 7 7 7 -1이 아닌, 5 7 7 -1이 나오는 것이다.

처음 문제 해결 방법은 단순하게 숫자를 받음과 동시에 배열과 스택을 쌓은 뒤 0번째 배열은 N-0번 반복, 1번째 배열은 N-1번 반복... 이런식으로 하나씩 비교하며 가까운 큰 수를 갱신하고 출력하는 것이었다.

그러나 이 진행 방법은 계속 스택과 배열을 반복 비교해야하고 한번 비교가 끝나면 스택을 다시 채워야해서, 반복문 2개가 겹친다. 그래서 O(n^2)의 시간 복잡도를 가지게 되어 결국 시간 초과로 실패했다.

그래서 고민 끝에 스택을 다시 채울 필요가 없게 배열을 뒤부터 비교해서 스택을 채우는 방식을 선택했다. 예를 들어 배열 [3, 5, 2, 7]에서 7->2->5->3 순으로 시작하면 스택은 없음->(7)->(7,2)->(7,2,5)이 된다.)


코드

  • 처음 코드(시간 초과로 실패)
#include <stdio.h>
#include <stdlib.h>
#include <stack>
using namespace std;

stack<int> s;
int N;
int *arr;

void fill_stack(int j) {
	for (int i = j; i < N; i++)
		s.push(arr[i]);
}

int main(int argc, char *argv[]) {
	int M;
	int *result;
	scanf("%d", &N);
	arr = (int *)malloc(sizeof(int) * N);
	result = (int *)malloc(sizeof(int) * N);

	for (int i = 0; i < N; i++) {
		scanf("%d", &M);
		s.push(M);
		arr[i] = M;
		result[i] = -1;		//초기화
	}

	for (int i = 0; i < N; i++) {
		int j = N - i;
		while (j) {
			if (s.top() > arr[i])
				result[i] = s.top();
			s.pop();
			j--;
		}
		fill_stack(j);
	}

	for (int i = 0; i < N; i++)
		printf("%d ", result[i]);

	return 0;
}
  • 완성 코드(성공)
#include <stdio.h>
#include <stdlib.h>
#include <stack>
using namespace std;

int main(int argc, char *argv[]) {
	int N, M;
	stack<int> s;
	scanf("%d", &N);

	int *arr = (int *)malloc(sizeof(int) * N);
	int *result = (int *)malloc(sizeof(int) * N);

	for (int i = 0; i < N; i++) {
		scanf("%d", &M);
		arr[i] = M;
	}

	for (int i = N-1; i >= 0; i--) {
		while (!s.empty() && s.top() <= arr[i])
			s.pop();

		if (s.empty())
			result[i] = -1;
		else
			result[i] = s.top();

		s.push(arr[i]);
	}

	for (int i = 0; i < N; i++)
		printf("%d ", result[i]);

	return 0;
}

결과

백준 제출 결과