문제 

4개의 기호 ‘(’, ‘)’, ‘[’, ‘]’를 이용해서 만들어지는 괄호열 중에서 올바른 괄호열이란 다음과 같이 정의된다.

  1. 한 쌍의 괄호로만 이루어진 ‘()’와 ‘[]’는 올바른 괄호열이다. 
  2. 만일 X가 올바른 괄호열이면 ‘(X)’이나 ‘[X]’도 모두 올바른 괄호열이 된다. 
  3. X와 Y 모두 올바른 괄호열이라면 이들을 결합한 XY도 올바른 괄호열이 된다.

예를 들어 ‘(()[[]])’나 ‘(())[][]’ 는 올바른 괄호열이지만 ‘([)]’ 나 ‘(()()[]’ 은 모두 올바른 괄호열이 아니다. 우리는 어떤 올바른 괄호열 X에 대하여 그 괄호열의 값(괄호값)을 아래와 같이 정의하고 값(X)로 표시한다. 

  1. ‘()’ 인 괄호열의 값은 2이다.
  2. ‘[]’ 인 괄호열의 값은 3이다.
  3. ‘(X)’ 의 괄호값은 2×값(X) 으로 계산된다.
  4. ‘[X]’ 의 괄호값은 3×값(X) 으로 계산된다.
  5. 올바른 괄호열 X와 Y가 결합된 XY의 괄호값은 값(XY)= 값(X)+값(Y) 로 계산된다.

예를 들어 ‘(()[[]])([])’ 의 괄호값을 구해보자. ‘()[[]]’ 의 괄호값이 2 + 3×3=11 이므로 ‘(()[[]])’의 괄호값은 2×11=22 이다. 그리고 ‘([])’의 값은 2×3=6 이므로 전체 괄호열의 값은 22 + 6 = 28 이다.

여러분이 풀어야 할 문제는 주어진 괄호열을 읽고 그 괄호값을 앞에서 정의한대로 계산하여 출력하는 것이다. 

 

입력

첫째 줄에 괄호열을 나타내는 문자열(스트링)이 주어진다. 단 그 길이는 1 이상, 30 이하이다.

 

출력 

첫째 줄에 그 괄호열의 값을 나타내는 정수를 출력한다. 만일 입력이 올바르지 못한 괄호열이면 반드시 0을 출력해야 한다. 

 

예제1

입력:

(()[[]])([])

출력

28

 

예제2

입력:

[][]((])

출력

0

 

 

코드

using System; 
using System.Text; 
using System.Collections.Generic; 

class Program 
{ 
    static void Main(string[] args) 
    { 
        List<char> bracket = new List<char>();
        List<string> prefix = new List<string>();
        List<int> productIndex = new List<int>();
        string str = Console.ReadLine();
        bool VPS = true;
        
        if(!str[0].Equals('(') && !str[0].Equals('[')) VPS = false;
        else 
        {
            bracket.Add(str[0]);
            prefix.Add(str[0].Equals('(') ? "2" : "3");
            
            for(int i=1; i<str.Length; i++) 
            { 
                if(!VPS) break;
                if(str[i].Equals('(') || str[i].Equals('['))
                {
                    int index = prefix.Count<2||bracket.Count==0 ? 0 : prefix.Count-1;

                    if(str[i-1].Equals('(') || str[i-1].Equals('[')) 
                    {
                        prefix.Insert(index, "*");
                        productIndex.Add(index+2);
                    }
                    else 
                    {
                        if(bracket.Count==0) prefix.Insert(0, "+");
                        else prefix.Insert(productIndex[bracket.Count-1], "+");
                    }
                    bracket.Add(str[i]);
                    prefix.Add(str[i].Equals('(') ? "2" : "3");
                }
                else if(str[i].Equals(')') || str[i].Equals(']'))
                {
                    if(bracket.Count==0) VPS = false;
                    else if(str[i].Equals(')'))
                    {
                        if(bracket[bracket.Count-1].Equals('(')) 
                        {
                            bracket.RemoveAt(bracket.Count-1);
                            if(str[i-1].Equals(')') || str[i-1].Equals(']')) productIndex.RemoveAt(productIndex.Count-1);
                        }
                        else VPS = false;
                    }
                    else if(str[i].Equals(']'))
                    {
                        if(bracket[bracket.Count-1].Equals('[')) 
                        {
                            bracket.RemoveAt(bracket.Count-1);
                            if(str[i-1].Equals(')') || str[i-1].Equals(']')) productIndex.RemoveAt(productIndex.Count-1);
                        }
                        else VPS = false;
                    }
                    if(bracket.Count==0) productIndex.Clear();
                }
                else VPS = false;
            }     
        }

        if(!VPS) Console.WriteLine("0"); 
        else if(bracket.Count>0) Console.WriteLine("0");
        else Console.WriteLine(calc(prefix.ToArray()));
    } 
    
    static string calc(string[] prefix)
    {
        List<string> stack = new List<string>();
        
        for(int i=0; i<prefix.Length; i++)
        {
            stack.Add(prefix[i]);
            int num1;
            int num2;
                
            while(stack.Count>2 && Int32.TryParse(stack[stack.Count-1], out num1) && Int32.TryParse(stack[stack.Count-2], out num2))
            {
                string operators = stack[stack.Count-3];
                stack.RemoveRange(stack.Count-3, 3);
                        
                switch(operators)
                {
                    case "+":
                        stack.Add((num1+num2).ToString());
                        break;
                    case "*":
                        stack.Add((num1*num2).ToString());
                        break;
                }
            }
        }
        return stack[0];
    }
}



참고

정답률이 28%인 이유가 있었다.

정답일거라고 생각했는데 예상치 못한 테스트 케이스에서 실패하고 수정하고 실패하고 수정하고..

코드가 다소 깔끔하지 못한 것 같아서 추후에 수정해보려고 한다. 

 

((()[])[])
답 26

(()[()]()[()])
답 32

(()[()]()[()])(()[()]()[()])
답 64

[](()[()]()[()])(()[()]()[()])
답 67

[](()[()]()[()])()(()[()]()[()])
답 69

[](()[()]()[()])()(()[()]()[()])[]
답 72

((()[()]()[()])()(()[()]()[()])[])
답 138

 

내가 적용했던 테스트 케이스들이고, 아래는 출처 링크다.

https://www.acmicpc.net/board/view/62519

 

 

'Coding > BaekJoon' 카테고리의 다른 글

[BaekJoon/C#] 15649. N과 M (1)  (0) 2021.10.03
[BaekJoon/C#] 4344. 평균은 넘겠지  (0) 2021.10.02
[BaekJoon/C#] 1920. 수 찾기  (0) 2021.09.25
[BaekJoon/C#] 9012. 괄호  (0) 2021.09.25
[BaekJoon/C#] 10773. 제로  (0) 2021.09.24

 

문제 

N개의 정수 A[1], A[2], …, A[N]이 주어져 있을 때, 이 안에 X라는 정수가 존재하는지 알아내는 프로그램을 작성하시오.

 

입력

첫째 줄에 자연수 N(1 ≤ N ≤ 100,000)이 주어진다. 다음 줄에는 N개의 정수 A[1], A[2], …, A[N]이 주어진다. 다음 줄에는 M(1 ≤ M ≤ 100,000)이 주어진다. 다음 줄에는 M개의 수들이 주어지는데, 이 수들이 A안에 존재하는지 알아내면 된다. 모든 정수의 범위는 -2^31 보다 크거나 같고 2^31보다 작다.

 

출력 

M개의 줄에 답을 출력한다. 존재하면 1을, 존재하지 않으면 0을 출력한다.

 

예제

입력:

5
4 1 5 2 3
5
1 3 7 9 5

출력

1
1
0
0
1

 

 

코드1 - while문

using System; 
using System.Text;

class Program 
{
    static void Main(string[] args) 
    { 
        StringBuilder sb = new StringBuilder();
        int totalC = int.Parse(Console.ReadLine());
        string[] str = Console.ReadLine().Trim().Split(); 
        int[] criteria = new int[str.Length];
        int totalS = int.Parse(Console.ReadLine());
        string[] search = Console.ReadLine().Trim().Split();

        for(int i=0; i<str.Length; i++)
        {
            criteria[i] = int.Parse(str[i]);
        }

        Array.Sort(criteria);
        
        for(int i=0; i<totalS; i++)
        {
            int low = 0;
            int high = criteria.Length-1;
            bool found = false;
            
            while(low<=high && !found) 
            {
                int mid = (low+high)/2;

                if(criteria[mid] == int.Parse(search[i])) found = true;
                else if(criteria[mid] > int.Parse(search[i])) high = mid-1;
                else low = mid+1;
            }
            sb.Append(found?"1\n":"0\n"); 
        }
        Console.WriteLine(sb.ToString()); 
    }
}

 

코드2 - 재귀함수

using System; 
using System.Text;

class Program
{ 
    static void Main(string[] args) 
    { 
        StringBuilder sb = new StringBuilder();
        int totalC = int.Parse(Console.ReadLine());
        string[] str = Console.ReadLine().Trim().Split(); 
        int[] criteria = new int[str.Length];
        int totalS = int.Parse(Console.ReadLine());
        string[] search = Console.ReadLine().Trim().Split();

        for(int i=0; i<str.Length; i++)
        {
            criteria[i] = int.Parse(str[i]);
        }

        Array.Sort(criteria);
        
        for(int i=0; i<totalS; i++)
        {
            sb.Append(BinarySearch(criteria, int.Parse(search[i]), 0, criteria.Length-1)? "1\n":"0\n"); 
        }
        
        Console.WriteLine(sb.ToString()); 
    } 

    static bool BinarySearch(int[] criteria, int element, int low, int high) 
    {
        if(low>high) return false;
        
        int mid = (low+high)/2;
        if(criteria[mid] == element) return true;
        else if(criteria[mid] > element) return BinarySearch(criteria, element, low, mid-1);
        else return BinarySearch(criteria, element, mid+1, high);
    }
}

 

 

참고

이 문제를 풀 때 처음에는 단순히 IndexOf를 사용했지만 '시간 초과'로 인해 다른 방법을 사용해야 했다. 

그래서 이진탐색을 이용해서 코드를 작성했더니 '시간 초과'는 아니었지만 '틀렸습니다'가 나왔다.

VSCode에서 돌려볼 땐 결과에 문제가 없었는데 왜 틀렸는지 알 수가 없었다. 

그래서 반례를 찾아보다가 백준 질문글에서 발견한 다른 사람의 반례를 넣어봤더니 출력 결과가 이상했다.

반례)
7
1234567890 12345 987654321 1357924680 -1234543210 -999999999 2147483647
7
1111111111 1234567890 987654321 0 12345 -999999999 -2122222222
정답)
0
1
1
0
1
1
0

출력)
0
1
0
0
1
1
0

 

왜 그런가 원인을 찾아봤더니 처음에 코드 짤 때 criteria를 int가 아닌 string 배열로 해서 Sort했더니 

string[] criteria = Console.ReadLine().Trim().Split(); 

Array.Sort(criteria);

 

[-1234543210]  [-999999999]  [12345]  [1234567890]  [1357924680]  [2147483647]  [987654321]

위 결과처럼 정렬됐다...

숫자의 첫 번째만 보고 정렬되어서 이상한 결과가 나왔던 것이다. 

그래서 입력받은 string을 str에 먼저 저장하고 다시 criteria에 int로 변환해서 저장했더니 해결됐다.

string[] str = Console.ReadLine().Trim().Split(); 
int[] criteria = new int[str.Length];
      
for(int i=0; i<str.Length; i++)
{
	criteria[i] = int.Parse(str[i]);
}

Array.Sort(criteria);

 

 

(추가)

코드3 - List<T>.BinarySearch 메소드

using System; 
using System.Text;
using System.Collections.Generic;

class Program
{ 
    static void Main(string[] args) 
    { 
        StringBuilder sb = new StringBuilder();
        int totalC = int.Parse(Console.ReadLine());
        string[] str = Console.ReadLine().Trim().Split(); 
        List<int> criteria = new List<int>();
        int totalS = int.Parse(Console.ReadLine());
        string[] search = Console.ReadLine().Trim().Split();

        for(int i=0; i<str.Length; i++)
        {
            criteria.Add(int.Parse(str[i]));
        }

        criteria.Sort();
        
        for(int i=0; i<totalS; i++)
        {
            int index = criteria.BinarySearch(int.Parse(search[i]));
            sb.Append(index < 0? "0\n":"1\n"); 
        }
        
        Console.WriteLine(sb.ToString()); 
    } 
}

 

 

'Coding > BaekJoon' 카테고리의 다른 글

[BaekJoon/C#] 4344. 평균은 넘겠지  (0) 2021.10.02
[BaekJoon/C#] 2504. 괄호의 값  (0) 2021.09.25
[BaekJoon/C#] 9012. 괄호  (0) 2021.09.25
[BaekJoon/C#] 10773. 제로  (0) 2021.09.24
[BaekJoon/C#] 10828. 스택 (시간초과 해결)  (0) 2021.09.24

 

문제 

괄호 문자열(Parenthesis String, PS)은 두 개의 괄호 기호인 ‘(’ 와 ‘)’ 만으로 구성되어 있는 문자열이다. 그 중에서 괄호의 모양이 바르게 구성된 문자열을 올바른 괄호 문자열(Valid PS, VPS)이라고 부른다. 한 쌍의 괄호 기호로 된 “( )” 문자열은 기본 VPS 이라고 부른다. 만일 x 가 VPS 라면 이것을 하나의 괄호에 넣은 새로운 문자열 “(x)”도 VPS 가 된다. 그리고 두 VPS x 와 y를 접합(concatenation)시킨 새로운 문자열 xy도 VPS 가 된다. 예를 들어 “(())()”와 “((()))” 는 VPS 이지만 “(()(”, “(())()))” , 그리고 “(()” 는 모두 VPS 가 아닌 문자열이다.

여러분은 입력으로 주어진 괄호 문자열이 VPS 인지 아닌지를 판단해서 그 결과를 YES 와 NO 로 나타내어야 한다.

 

입력

입력 데이터는 표준 입력을 사용한다. 입력은 T개의 테스트 데이터로 주어진다. 입력의 첫 번째 줄에는 입력 데이터의 수를 나타내는 정수 T가 주어진다. 각 테스트 데이터의 첫째 줄에는 괄호 문자열이 한 줄에 주어진다. 하나의 괄호 문자열의 길이는 2 이상 50 이하이다. 

 

출력 

출력은 표준 출력을 사용한다. 만일 입력 괄호 문자열이 올바른 괄호 문자열(VPS)이면 “YES”, 아니면 “NO”를 한 줄에 하나씩 차례대로 출력해야 한다. 

 

예제1

입력:

6
(())())
(((()())()
(()())((()))
((()()(()))(((())))()
()()()()(()()())()
(()((())()(

출력

NO
NO
YES
NO
YES
NO

 

예제2

입력:

3
((
))
())(()

출력

NO
NO
NO

 

 

코드

using System; 
using System.Text;
using System.Collections.Generic;

class Program 
{ 
    static void Main(string[] args) 
        { 
            int total = int.Parse(Console.ReadLine());
            List<char> bracket = new List<char>();
            StringBuilder sb = new StringBuilder();
            
            for(int i=0; i<total; i++)
            {
                string str = Console.ReadLine().Trim();
                bool VPS = true;
                bracket.Clear();
                for(int j=0; j<str.Length; j++)
                {
                    if(!VPS) break;
                    if(str[j].Equals('(')) bracket.Add(str[j]);
                    else if(str[j].Equals(')'))
                    {
                        if(bracket.Count>0) bracket.RemoveAt(bracket.Count-1);
                        else VPS = false;
                    }
                }
                if(!VPS) sb.Append("NO\n");
                else sb.Append(bracket.Count == 0? "YES\n" : "NO\n" );
            }
            Console.WriteLine(sb.ToString());
        }
}



참고

이 문제 코드에서는 문제 없어 보였는데 계속 '틀렸습니다'만 뜨길래 도대체 뭐가 잘못된걸까 싶었다..

알고보니 for문 돌면서 다음 괄호열 받아올 때 bracket List를 Clear() 해주지 않아서 

이전에 저장했던 값이 남아 잘못된 결과를 도출했던 것이다. 

 

 

'Coding > BaekJoon' 카테고리의 다른 글

[BaekJoon/C#] 2504. 괄호의 값  (0) 2021.09.25
[BaekJoon/C#] 1920. 수 찾기  (0) 2021.09.25
[BaekJoon/C#] 10773. 제로  (0) 2021.09.24
[BaekJoon/C#] 10828. 스택 (시간초과 해결)  (0) 2021.09.24
[BaekJoon/C#] 1316. 그룹 단어 체커  (0) 2021.09.23

+ Recent posts