새소식

Computer Science/코딩테스트 문제 풀이

⭐⭐⭐[백준] [파이썬] [스택] 3015번: 오아시스 재결합

  • -

문제집 추천, 이 문제집에 나온 유형들만 공부해도 코딩테스트는 거뜬: https://www.acmicpc.net/workbook/by/BaaaaaaaaaaarkingDog

 

3015번: 오아시스 재결합 문제보기

 

3015번: 오아시스 재결합

첫째 줄에 줄에서 기다리고 있는 사람의 수 N이 주어진다. (1 ≤ N ≤ 500,000) 둘째 줄부터 N개의 줄에는 각 사람의 키가 나노미터 단위로 주어진다. 모든 사람의 키는 231 나노미터 보다 작다. 사람

www.acmicpc.net

제한시간: 1초
메모리 제한: 256 MB

문제

오아시스의 재결합 공연에 N명이 한 줄로 서서 기다리고 있다.

이 역사적인 순간을 맞이하기 위해 줄에서서 기다리고 있던 백준이는 갑자기 자기가 볼 수 있는 사람의 수가 궁금해 졌다.

두 사람 A와 B가 서로 볼 수 있으려면, 두 사람 사이에 A 또는 B보다 키가 큰 사람이 없어야 한다.

줄에 서있는 사람의 키가 주어졌을 때, 서로 볼 수 있는 쌍의 수를 구하는 프로그램을 작성하시오.

입력

첫째 줄에 줄에서 기다리고 있는 사람의 수 N이 주어진다. (1 ≤ N ≤ 500,000)

둘째 줄부터 N개의 줄에는 각 사람의 키가 나노미터 단위로 주어진다. 모든 사람의 키는 231 나노미터 보다 작다.

사람들이 서 있는 순서대로 입력이 주어진다.

출력

서로 볼 수 있는 쌍의 수를 출력한다.

예제 입력 1

7
2
4
1
2
2
5
1

예제 출력 1

10


어렵다. 너무 어려워. 아무리 해도 9가 나오고 답을 못찾았다.

우선 나는 2가지로 생각했다. 예제에서 [2,4,1,2,2,5,1] 인경우

  1. 생각 1
    2 -> 4
    4 -> 1,2,2,5
    1 -> 2
    2 -> 2,5
    2 -> 5
    5 -> 1
    1 -> 0
    총 10개

이런식으로 왼쪽부터 오른쪽으로 중복없이 쌍을 찾아가는 것을 생각했다. 그러나 스텍을 이용해서는 방법을 찾을 수 없었다.

  1. 생각 2
    2 -> x
    4 -> 2
    1 -> 4
    2 -> 1,4
    2 -> 2,4
    5 -> 2,2,4
    1 -> 5
    총 10개

처음 2는 stack에 넣고
4부터 stack을 뽑아보며 자기 자신과 비교해서 증가시키면 된다고 생각했다.

 

+ 추가 

생각 2와 같은 방식은 옳은 방향이다. 내가 코드 구현을 못하였던거였다.


틀린 내 코드

import sys 
sys.stdin=open('input.txt','r')

if __name__=="__main__":
    N=int(input())
    stack=[]
    res=[0]*N            # 내 생각과 맞게 돌아가는지 보기 위해 
    for i in range(N):
        x=int(input())
        while stack:
            res[i]+=1
            if x>stack[-1]:
                stack.pop()
            else:
                break

        stack.append(x)


    # i를 넣을지, x를 넣을지, 아님 둘다 넣을지 고민
    print(res)
    print(sum(res))

[0,1,1,2,1,3,1]
9
뭔가 아슬아슬하게 답이 나오지 않았다.
원하는 답은
[0,1,1,2,2,3,1]
10
이어야 하는데 답이 안나온다.


정답 코드

import sys 
sys.stdin=open('input.txt','r')

if __name__=="__main__":
    N=int(input())
    stack=[]
    res=[0]*N
    for i in range(N):
        x=int(input())
        while stack:
            if x>stack[-1][0]:          # 현재 키가 이전 사람 키보다 크면 
                res[i]+=stack.pop()[1]  # 현재 사람에게 한쌍 주어줌 
            else:
                break

        if not stack:               # stack이 비어있을때, 제일 먼저 이뤄질 코드 
            stack.append([x,1])     # 현재 사람이 이전 사람보다 키가 컸을때도

        elif stack[-1][0]==x:       # stack에 마지막 사람 키가 현재 사람 키와 같으면
            cnt=stack.pop()[1]
            res[i]+=cnt         
            if stack:               # 키가 같은 사람끼리는 자기보다 작은 사람 통과해서 쌍이룰 수 있음
                res[i]+=1
            stack.append([x,cnt+1])

        else:                    # stack에 마지막 사람 키가 현재 사람 키와 다르면
            stack.append([x,1])  # 일단 쌓아두고 
            res[i]+=1            # 쌍은 추가    

    # print(res)
    print(sum(res))

이걸 어케 풀어....


예제는 다음과 같은 순서로 진행된다. 

 

2,4,1,2,2,5,1

x: 2
stack: [[2,1]]
res=[0,0,0,0,0,0,0]

x: 4
res=[0,1,0,0,0,0,0] 4에서 2가 보임 
stack: [[4,1]]

x: 1
res=[0,1,1,0,0,0,0] 1에서 4가 보임 
stack: [[4,1],[1,1]]

x: 2
res=[0,1,1,1,0,0,0] 2에서 1이 보임 
stack: [[4,1]]
res=[0,1,1,2,0,0,0] 2에서 4가 보임 
stack: [[4,1],[2,1]]

x: 2 
앞에 사람의 키가 같음 
stack: [[4,1]]
res=[0,1,1,2,1,0,0] 현재 2에서 2가 보임  
res=[0,1,1,2,2,0,0] 현재 2에서 4가 보임 (1은 안보)
stack: [[4,1],[2,2]]

x: 5 
stack: [[4,1]]
res=[0,1,1,2,2,2,0] 현재 5는 앞에 2인 사람 두명이 보임 
stack: []
res=[0,1,1,2,2,3,0] 현재 5는 앞에 4가 보임 
stack: [[5,1]]

x: 1
stack: [[5,1],[1,1]]
res=[0,1,1,2,2,3,1]

합: 1+1+2+2+3+1=10

Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.