Notice
Recent Posts
Recent Comments
Link
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Tags
more
Archives
Today
Total
관리 메뉴

대웅짱님의 블로그

[프로그래머스] 쇠막대기 본문

알고리즘/프로그래머스

[프로그래머스] 쇠막대기

대웅짱 2019. 4. 1. 20:50

문제: https://programmers.co.kr/learn/courses/30/lessons/42585



오늘은 프로그래머스 [스택/큐] 문제 중 쇠막대기를 소개할까 한다.


사실 이건 백준에서도 풀었었던 문제인데


여기에도 있어서 반가워서 포스팅 할려고 한다.


문제는 '(' 와 ')' 로 이루어진 문자열이 주어졌을 때


최종적으로 쇠막대기가 몇 개로 나누어 지는지 물어보는 문제이다.


만약 '( )' 처럼 괄호의 열림과 닫힘이 연속적으로 주어진다면


레이저를 쏘아서 현재 놓여져 있는 쇠막대기를 나눌 수 있다.


문제푸는 아이디어는 스택/큐 문제이지만


굳이 스택/큐를 사용할 필요는 없다.


간단한 규칙찾기로도 이 문제를 해결할 수 있다.


문제에도 있는 예제인


( ) ( ( ( ( ) ( ) ) ( ( ) ) ( ) ) ) ( ( ) ) 로 설명하겠다.


이것만 기억하면 된다.


1. '( )'는 레이저를 쏘아서 현재 놓여져 있는 쇠막대기를 나눈다. => 즉, 레이저의 위치에 놓여진 쇠막대기만큼 개수 추가


2. 홀로 사용 된 '('의 의미는 하나의 쇠막대기를 추가해서 놓는 것.


3. 홀로 사용 된 ')'의 의미는 하나의 쇠막대기 길이가 끝난 것.


현재 놓여진 쇠막대기 개수를 cnt, 최종적인 쇠막대기 개수를 res라고 정의하고 예제를 순서대로 진행해 보겠다.


( => cnt++;            cnt = 1, res = 0

) => 바로전 '('이었으므로 레이저이다. cnt--, res += cnt;            cnt = 0, res = 0

                                  레이저일 땐 '('가 쇠막대기를 의미하는 것이 아니므로 위에서 '('로 인해 더해진 cnt를 하나 뺀다.

( => cnt++;            cnt = 1, res = 0

( => cnt++;            cnt = 2, res = 0

( => cnt++;            cnt = 3, res = 0

( => cnt++;            cnt = 4, res = 0

) => 레이저. cnt--, res += cnt;            cnt = 3, res = 3

( => cnt++;            cnt = 4, res = 3

) => 레이저. cnt--, res += cnt;            cnt = 3, res = 6

) => 쇠막대기 하나의 길이가 끝남. 끝난 쇠막대기의 마지막 조각을 더해준다. cnt--, res++;            cnt = 2, res = 7

( => cnt++;            cnt = 3, res = 7

( => cnt++;            cnt = 4, res = 7

) => 레이저. cnt--, res += cnt;            cnt = 3, res = 10

) => cnt--, res-++;            cnt = 2, res = 11

( => cnt++;            cnt = 3, res = 11

) => 레이저. cnt--, res += cnt            cnt = 2, res = 13

) => cnt--, res++;            cnt = 1, res = 14

) => cnt--, res++;            cnt = 0, res = 15

( => cnt++;            cnt = 1, res = 15

( => cnt++;            cnt = 2, res = 15

) => 레이저. cnt--, res += cnt            cnt = 1, res = 16

) => cnt--, res++;            cnt = 0, res = 17


이렇게 마지막까지 도달했을 때 cnt는 0이 되어야 모든 쇠막대기를 처리한 것이다.


추가적으로 어떻게 이렇게 해도 되는지가 궁금할 수 있는데


이 문제의 조건인


- 쇠막대기는 자신보다 긴 쇠막대기 위에만 놓일 수 있습니다.
- 쇠막대기를 다른 쇠막대기 위에 놓는 경우 완전히 포함되도록 놓되, 끝점은 겹치지 않도록 놓습니다.
- 각 쇠막대기를 자르는 레이저는 적어도 하나 존재합니다.
- 레이저는 어떤 쇠막대기의 양 끝점과도 겹치지 않습니다.


위의 네 가지 조건 덕분에 가능하다.



- 쇠막대기는 자신보다 긴 쇠막대기 위에만 놓일 수 있습니다.


=> 먼저 생긴 '(' 가 가장 길다. 덕분에 열고 닫는 괄호의 개수와 순서는 짝을 이룬다. ( ( ( ) ) 즉, '('마다 cnt++을 해주어도 되는 것이다.


- 쇠막대기를 다른 쇠막대기 위에 놓는 경우 완전히 포함되도록 놓되, 끝점은 겹치지 않도록 놓습니다.


=> 중요한 점은 끝점이 겹치지 않는다는 점이다. 이 조건 덕분에 닫힌 괄호가 하나 생겼을 때 cnt--, res++을 해도 문제가 없는 것이다.


- 각 쇠막대기를 자르는 레이저는 적어도 하나 존재합니다.


=> 마지막까지 진행했을 때 cnt가 0으로 끝날 수 있는 조건이다.


- 레이저는 어떤 쇠막대기의 양 끝점과도 겹치지 않습니다.


=> 레이저를 쏘았을 때 cnt--, res += cnt를 할 수 있는 이유다. 레이저가 쇠막대기와 겹치는 경우가 없기 때문에 마음 편히 cnt를 더해줄 수 있는 것이다. 


끝.






1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <string>
#include <vector>
 
using namespace std;
 
int solution(string arrangement) {
    int answer = 0;
    int cnt = 0;
    int res = 0;
    for(int i=0; i<(int)arrangement.size(); i++){
        if(arrangement[i] == '('){
            cnt++;
        }else{
            if(arrangement[i-1== '('){
                cnt--;
                res += cnt;
            }else{
                res++;
                cnt--;
            }
        }
    }
    answer = res;
    return answer;
}
cs


'알고리즘 > 프로그래머스' 카테고리의 다른 글

[프로그래머스] 베스트앨범  (0) 2019.03.29