[백준] 2493번 탑

2025. 1. 7. 15:22·백준 문제/자료구조

문제: 2493번: 탑

basic-algo-lecture/workbook/0x05.md at master · encrypted-def/basic-algo-lecture

 

basic-algo-lecture/workbook/0x05.md at master · encrypted-def/basic-algo-lecture

바킹독의 실전 알고리즘 강의 자료. Contribute to encrypted-def/basic-algo-lecture development by creating an account on GitHub.

github.com

 

#include <map>
#include <set>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <iostream>
#include <algorithm>
#include <iomanip> // setprecision을 사용하기 위한 헤더
#include <climits>
#include <list>

using namespace std;


int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    int n; // 탑의 수
    cin >> n;
    vector<int> answer;

    int prev = -1;
    // first: 높이, second: 인덱스
    stack<pair<int, int>> enableTops; // 왼쪽 오른쪽의 값이 자기보다 작은 탑들 저장
    for (int i = 0; i < n; i++) {
        bool flag = false;

        int cur;
        cin >> cur;

        pair<int, int> largerTop; // 자기보다 큰 탑 저장

        // enableTops 는 아래에 있는 요소가 위에 있는 요소의 값보다 작을수가 없음!!
        // 왜? 새로운 값을 넣으려고 할 때, 이 값보다 작은 요소들은 다 없애버리니까
        while (!enableTops.empty()) {
            pair<int, int> prev = enableTops.top();

            if (prev.first <= cur) {
                enableTops.pop();
            }
            else {
                flag = true; // 자기 보다 큰 걸 만나면 멈췅
                largerTop = prev;
                break;
            }
        }
        enableTops.push(make_pair(cur, i)); // 현재 값 넣어주기


        if (flag)
            answer.push_back(largerTop.second + 1); // 자신보다 큰 탑의 번호
        else
            answer.push_back(0); // 자신보다 큰 값이 없으면 0
    }

    for (int i = 0; i < n; i++)
        cout << answer[i] << " ";


    return 0;
}

 

1년 전에 못 풀었던 문제를 드디어 풀었다.

 

일단 이 문제를 해결할 수 있는 방법은 왼쪽에서부터 차례로 조건을 확인해가면서 스택을 이용하는 것이다.

 

처음에는 맨 오른쪽 요소가 top 에 있고, 그래서 뒤에서부터 값을 비교하면서 빼는식으로 하려고 했는데 이렇게 하면 시간 복잡도가 O(n^2) 이라 절대 문제를 해결할 수 없어보였다. 왜냐면 n 의 범위가 1부터 500,000 까진데 이거를 O(n^2) 으로 풀면 도저히 1.5초 만에 해결할 수 없기 때문이다.

 

그래서 다음에 생각한 건 맨 앞 요소부터 차례대로 스택에 넣어가면서 현재 스택에 넣으려는 값이랑 스택의 top 값이랑 비교했을 때, 현재 값이 더 크면 large 의 값을 현재 값으로 바꿔줄까였다. 왜냐면 이전 값이 현재 값보다 작으면 이전 값은 현재 값 다음으로 들어올 탑한테는 그냥 없는 것과 마찬가지라고 생각했기 때문이다.

 

근데 위와 같은 방법으로 하면 또 생기는 문제점이 현재 stack 의 값 중 무조건 가장 큰 값과 비교하기 때문에 현재 들어오는 값보다는 크지만 large 보다는 작아서 large 보다 더 가까이 있는 조건을 만족하는 탑이 존재하는 경우가 있을 때, 이를 체크를 못 하는 것이었다.

 

맨 앞 요소부터 차례대로 스택에 넣어가면서 연산을 수행하는 방식을 그대로 가져가되 다른 방식이 필요했다. 그래서 생각을 해봤는데 stack 에 수신 가능한 애들만 남겨놓는 식의 방식이 떠올랐다. 내가 생각한 수신 가능한 탑의 조건은 그냥 자기 뒤로 들어오는 값보다 크면 되는 것이었다. 앞에 자기보다 더 큰 값이 있는지는 상관없다. 그냥 내 뒤에 들어오려는 애가 나보다 작기만 하면 수신 가능한 탑이다.

 

그래서 특징을 발견했는데, 스택 요소는 top 으로 갈수록 값이 작아진다는 것이었다. 문제 풀고나서 봤더니 이걸 모노톤 스택이라고 하더라.. 새로운 걸 또 알게 되었다.

 

아무튼 그래서 현재 값보다 작은 top 들의 값을 스택에서 빼주고, 만약 큰 값이 있다면 거기서 while 을 끝내고 다음 for 문으로 넘어가는 식으로 구현했다.

 

사실 수식만 보면 for 문 안에 while 문이 있어서 시간 복잡도를 O(n^2) 으로 생각할 수 있지만 while 문에서는 현재 값보다 작은 값을 다 빼주고 있으므로 다음 for 문에선 뺀 값들을 마주할 수 없다. 그래서 n^2 이 될 수 없다. 사실 이거 마음으로는 받아들였는데 증명은 못하겠다;; 정리해놓은 글 있어서 좀 찾아왔는데 참고자료에 남겨놓으려고 한다.

 

아, 그리고 자신보다 큰 탑을 마주했을 때 그 탑의 번호를 쉽게 확인하기 위해서 stack 에 넣는 요소의 타입을 pair<int, int> 로 해줬다. first 요소는 탑의 높이, second 요소는 탑의 번호로 설정하니까 쉽게 할 수 있었다.

 

^~^ 1년 전과 비교했을 때 확실히 성장한 것 같긴 하다. 다행이다 ^_^ 더 열심히 해야겠다.

 

 

 

참고자료:

1. 모노톤 스택

모노톤 스택 Monotone Stack (JAVA)

 

모노톤 스택 Monotone Stack (JAVA)

📍 모노톤 스택이란? : 스택 변형된 형태이다. 모노톤은 단조(monotonic)에서 유래된 말로, 스택 내에 저장된 데이터들이 단조 증가 또는 단조 감소하는 성질을 가지도록 유지하는 자료 구조이다. 1

velog.io

 

2. 시간복잡도가 O(n^2) 이 아닌 걸 잘 설명한 글

[백준 2493번] 탑

 

[백준 2493번] 탑

n = int(input()) tops = list(map(int,input().split())) answer = [0 for _ in range(n)] stack = [] for i,value in enumerate(tops): while stack: if stack[-1][1]

woohyun-king.tistory.com

 

'백준 문제/자료구조' 카테고리의 다른 글
  • [백준] 11279번 최대 힙
  • [백준] 2164번 카드2
  • [백준] 10828번 스택
  • [백준] 5397번 키로거
dubu0721
dubu0721
dubu0721 님의 블로그 입니다.
  • dubu0721
    dubu0721 님의 블로그
    dubu0721
  • 전체
    오늘
    어제
    • 분류 전체보기 (336) N
      • 프로그래밍언어론 정리 (0)
      • 컴퓨터네트워크 정리 (5)
      • 알고리즘&자료구조 공부 (64)
        • it 취업을 위한 알고리즘 문제풀이 입문 강의 (60)
        • 학교 알고리즘 수업 (3)
        • 실전프로젝트I (0)
      • 백준 문제 (194) N
        • 이분탐색 (7)
        • 투포인트 (10)
        • 그래프 (7)
        • 그리디 (24)
        • DP (25)
        • BFS (16) N
        • MST (7)
        • KMP (4)
        • Dijkstra (3)
        • Disjoints Set (4)
        • Bellman-Ford (2)
        • 시뮬레이션 (3)
        • 백트래킹 (15)
        • 위상정렬 (5)
        • 자료구조 (25)
        • 기하학 (1)
        • 정렬 (11)
        • 구현 (8)
        • 재귀 (8)
        • 수학 (8)
      • 유니티 공부 (11)
        • 레트로의 유니티 게임 프로그래밍 에센스 (11)
        • 유니티 스터디 자료 (0)
        • C# 공부 (0)
      • 유니티 프로젝트 (48)
        • 케이크게임 (13)
        • 점토게임 (35)
      • 언리얼 공부 (10)
        • 이득우의 언리얼 프로그래밍 (10)
      • 진로 (1)
      • 논문 읽기 (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    C#
    유니티
    해시
    레트로의 유니티 프로그래밍
    바킹독
    이분탐색
    BFS
    큐
    이득우
    백트래킹
    우선순위큐
    언리얼
    유니티 프로젝트
    시뮬레이션
    골드메탈
    투포인터
    이벤트 트리거
    수학
    자료구조
    그리디
    dp
    오블완
    맵
    티스토리챌린지
    백준
    스택
    정렬
    그래프
    재귀
    유니티 공부 정리
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
dubu0721
[백준] 2493번 탑
상단으로

티스토리툴바