제가 공부한 내용을 정리하는 블로그입니다.
아직 많이 부족하고 배울게 너무나도 많습니다. 틀린내용이 있으면 언제나 가감없이 말씀해주시면 감사하겠습니다😁
SWEA 1256 K번째 접미어입니다.

 

해당 문제도 솔직히 효율적인 코드인지는 잘 모르겠습니다만, 제가 활용한 알고리즘을 정리하겠습니다.

포인트

Java의 substring() method를 활용하여, 접미어를 구하고, Collections.sort를 진행합니다.

그 이후 k번째 접미어를 찾아줍니다.

소스코드

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Q1256 {
    private static int tc, K;
    private static List<String> postfix;

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        tc = Integer.parseInt(br.readLine());
        StringBuilder sb = new StringBuilder();
        for (int t = 1; t <= tc; t++) {
            K = Integer.parseInt(br.readLine());
            String line = br.readLine();

            postfix = new ArrayList<>();
            for (int i = 0; i < line.length(); i++) {
                postfix.add(line.substring(i));
            }

            Collections.sort(postfix);

            sb.append("#").append(t).append(" ")
                    .append(postfix.size() >= K ? postfix.get(K-1) : "none").append("\n");
        }
        System.out.println(sb);
    }
}

코드 설명

postfix = new ArrayList<>();
for (int i = 0; i < line.length(); i++) {
    postfix.add(line.substring(i));
}

Collections.sort(postfix);
  • index가 i부터인 substring을 postfix에 넣어주고, 정렬을 진행해줍니다.
  • 그 이후 k번째 접미어를 찾고 만약 없으면 none을 반환해줍니다.
제가 공부한 내용을 정리하는 블로그입니다.
아직 많이 부족하고 배울게 너무나도 많습니다. 틀린내용이 있으면 언제나 가감없이 말씀해주시면 감사하겠습니다😁
SWEA 1259 금속막대입니다.

포인트

문제의 포인트를 잡기 앞서, 조건을 몇개 추가하여야 문제의 해결이 가능합니다.

첫째, 나사들의 중복은 존재하지 않아야합니다. 예를 들어 숫나사의 값들에는 중복이 없으며, 암나사의 값들에는 중복이 없습니다.

둘째, 남는 나사는 없습니다. 즉 모든 나사는 연결이 가능합니다.

 

이러한 조건을 바탕으로 맨 첫번째 숫나사는 어떠한 나사의 암나사와도 일치하지 않음을 알 수 있습니다.

첫번째 나사를 기준으로 암나사의 값과 숫나사의 값이 일치하는 나사를 찾고 그 다음 나사로 반복해주면 문제를 해결할 수 있습니다.

소스코드

import java.io.*;
import java.util.*;

public class Q1259 {
    static int T, N;
    static Map<Integer, Integer> chain;
    static Map<Integer, Integer> revChain;

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        T = Integer.parseInt(br.readLine());

        StringBuilder sb = new StringBuilder();

        for (int t = 1; t <= T; t++) {
            N = Integer.parseInt(br.readLine());
            StringTokenizer st = new StringTokenizer(br.readLine());

            chain = new HashMap<>();
            revChain = new HashMap<>();

            for (int i = 0; i < N; i++) {
                int male = Integer.parseInt(st.nextToken());
                int female = Integer.parseInt(st.nextToken());
                chain.put(male, female);
                revChain.put(female, male);  // 역방향도 저장
            }

            // 시작점 찾기: 수나사인데, 누구의 암나사에도 안 쓰인 것
            int start = -1;
            for (int key : chain.keySet()) {
                if (!revChain.containsKey(key)) {
                    start = key;
                    break;
                }
            }

            sb.append("#").append(t);

            // 체인 순서대로 출력
            while (chain.containsKey(start)) {
                int end = chain.get(start);
                sb.append(" ").append(start).append(" ").append(end);
                start = end;
            }

            sb.append("\n");
        }

        System.out.print(sb);
    }
}

코드 설명

  • 암나사와 숫나사의 중복이 존재하지 않기에 이를 저장하는 자료구조 Map을 사용합니다.
    • chain: 숫나사가 key고 암나사가 value인 map
    • revChain: 암나사가 key 숫나가사 value인 map
int start = -1;
for (int key : chain.keySet()) {
    if (!revChain.containsKey(key)) {
        start = key;
        break;
    }
}
  • 숫나사의 value가 어떠한 암나사와도 일치하지 않는 나사 찾기
while (chain.containsKey(start)) {
    int end = chain.get(start);
    sb.append(" ").append(start).append(" ").append(end);
    start = end;
}
  • map을 순회하면서 나사의 연결을 찾습니다.
제가 공부한 내용을 정리하는 블로그입니다.
아직 많이 부족하고 배울게 너무나도 많습니다. 틀린내용이 있으면 언제나 가감없이 말씀해주시면 감사하겠습니다😁
SWEA 1265 달란트2입니다.

포인트

해당 문제는 수학을 사용하는 문제였습니다.

합이 같은 두 수열이라도, 수들의 차이가 적을수록 곱이 더 커집니다.

예를 들어:
- 6을 2와 4로 나누면 곱은 8
- 6을 3과 3으로 나누면 곱은 9 ✅

즉, 곱해지는 수가 서로 비슷할수록 곱의 값은 더 커집니다.
이 성질을 이용하면, 복잡한 탐색 없이 곱의 최댓값을 수학적으로 계산할 수 있습니다.

소스코드

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class Q1265 {
    private static int tc, N, P;

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        tc = Integer.parseInt(br.readLine());

        StringBuilder sb = new StringBuilder();
        StringTokenizer st;
        for (int t = 1; t <= tc; t++) {
            st = new StringTokenizer(br.readLine());
            N = Integer.parseInt(st.nextToken());
            P = Integer.parseInt(st.nextToken());

            int q = N / P;
            int r = N % P;

            long result = 1;
            for (int i = 0; i < r; i++) {
                result *= (q + 1);
            }
            for (int i = r; i < P; i++) {
                result *= q;
            }

            sb.append("#").append(t).append(" ").append(result).append("\n");
        }

        System.out.println(sb);
    }
}

코드 설명

  • q는 몫, r은 나머지입니다.
  • r만큼 몫+1 값을 곱해주고
  • p만큼 몫을 곱해줍니다.
제가 공부한 내용을 정리하는 블로그입니다.
아직 많이 부족하고 배울게 너무나도 많습니다. 틀린내용이 있으면 언제나 가감없이 말씀해주시면 감사하겠습니다😁
SWEA 1248 공통조상입니다.

먼저 효율적인 풀이인지는 사실 잘 모르겠습니다. 제가 푼 방법만 공유드리겠습니다.
(후에 찾아보니 binary lifting 방법이 있더라구요. 추후에 공부 후 포스팅하도록 하겠습니다.)

포인트

트리의 특성을 활용한 문제입니다.

트리의 각 노드는 depth가 존재하고 같은 depth로 만들고 그 부모가 같은지 확인하고 다르다면 부모 노드로 이동하는 로직으로 구성했습니다.

소스코드

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;

public class Q1248 {
    static class Node {
        int parent, depth;
        int childCnt = 0;

        public Node(int parent, int depth) {
            this.parent = parent;
            this.depth = depth;
        }
    }

    private static int testCase, V, E, a, b;
    private static Node[] parents;
    private static List<List<Integer>> list = new ArrayList<>();

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        testCase = Integer.parseInt(br.readLine());

        StringBuilder sb = new StringBuilder();
        StringTokenizer st;
        for (int t = 1; t <= testCase; t++) {
            st = new StringTokenizer(br.readLine());
            V = Integer.parseInt(st.nextToken());
            E = Integer.parseInt(st.nextToken());
            a = Integer.parseInt(st.nextToken());
            b = Integer.parseInt(st.nextToken());

            init();

            st = new StringTokenizer(br.readLine());
            for (int i = 0; i < E; i++) {
                int parent = Integer.parseInt(st.nextToken());
                int child = Integer.parseInt(st.nextToken());
                parents[child] = new Node(parent, parents[parent].depth + 1);
                parents[parent].childCnt++;
                list.get(parent).add(child);
            }

            for (int i = 1; i <= V; i++) {
                if (parents[i].parent == i && !list.get(i).isEmpty()) {
                    setDepth(i, 0);
                }
            }

            int grand = findCommonGrand();
            int childCnt = findChildCnt(grand);

            sb.append("#").append(t).append(" ").append(grand).append(" ").append(childCnt);
            if (t != testCase) {
                sb.append("\n");
            }
        }
        System.out.println(sb);
    }

    private static int findChildCnt(int root) {
        int cnt = 1;
        Queue<Integer> q = new LinkedList<>();
        q.add(root);

        while (!q.isEmpty()) {
            int parent = q.poll();

            for (int child : list.get(parent)) {
                cnt++;
                q.add(child);
            }
        }
        return cnt;
    }

    private static int findCommonGrand() {
        int n1 = a;
        int n2 = b;

        while (n1 != n2) {
            while(parents[n1].depth > parents[n2].depth) {
                n1 = parents[n1].parent;
            }
            while (parents[n1].depth < parents[n2].depth) {
                n2 = parents[n2].parent;
            }

            while(n1 != n2) {
                n1 = parents[n1].parent;
                n2 = parents[n2].parent;
            }
        }
        return n1;
    }

    private static void init() {
        parents = new Node[V + 1];
        for (int i = 0; i <= V; i++) {
            parents[i] = new Node(i, 0);
        }

        list = new ArrayList<>();
        for (int i = 0; i <= V; i++) {
            list.add(new ArrayList<>());
        }
    }

    private static void setDepth(int curr, int depth) {
        parents[curr].depth = depth;
        for (int child : list.get(curr)) {
            setDepth(child, depth + 1);
        }
    }
}

코드 설명

static class Node {
    int parent, depth;
    int childCnt = 0;

    public Node(int parent, int depth) {
        this.parent = parent;
        this.depth = depth;
    }
}
  • Node class
    현재 노드의 부모노드(parent), depth와 자식 카운트를 인스턴스 변수를 선언합니다.
private static void setDepth(int curr, int depth) {
    parents[curr].depth = depth;
    for (int child : list.get(curr)) {
        setDepth(child, depth + 1);
    }
}
  • setDepth(int curr, int depth)
    depth를 설정하는 함수
    • curr을 기준으로 dfs 탐색하면서 depth를 설정합니다.
private static int findCommonGrand() {
    int n1 = a;
    int n2 = b;

    while (n1 != n2) {
        while(parents[n1].depth > parents[n2].depth) {
            n1 = parents[n1].parent;
        }
        while (parents[n1].depth < parents[n2].depth) {
            n2 = parents[n2].parent;
        }

        while(n1 != n2) {
            n1 = parents[n1].parent;
            n2 = parents[n2].parent;
        }
    }
    return n1;
}
  • findCommonGrand()
    공통 조상을 찾는 함수
    • node a와 b에 대해, depth를 일치시킨 후 그 둘의 부모가 같은지 파악합니다.
private static int findChildCnt(int root) {
    int cnt = 1;
    Queue<Integer> q = new LinkedList<>();
    q.add(root);

    while (!q.isEmpty()) {
        int parent = q.poll();

        for (int child : list.get(parent)) {
            cnt++;
            q.add(child);
        }
    }
    return cnt;
}
  • findChildCnt(int root)
    서브 트리의 자식 카운트 숫자를 구하는 함수
    • 자기 자신을 더하고 자식 수를 구합니다.
제가 공부한 내용을 정리하는 블로그입니다.
아직 많이 부족하고 배울게 너무나도 많습니다. 틀린내용이 있으면 언제나 가감없이 말씀해주시면 감사하겠습니다😁
SWEA 1210 Ladder1입니다.

포인트

사다리 타기 게임에 포인트는 아래로만 향하다가 갈래를 만났을 때 무조건 그쪽 방향으로 간다는 것입니다.

100x100의 배열이기에 시작하는 위치(i==0이고 값이 1인) 위치를 기억하여 해당 위치에서 사다리를 탔을 때
목적지에 도착하도록 구현하는 문제입니다.

소스코드

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;

public class Q1210 {
    static class Pair {
        int x, y, dir;

        public Pair(int x, int y) {
            this.x = x;
            this.y = y;
            this.dir = 3;
        }

        public Pair(int x, int y, int dir) {
            this.x = x;
            this.y = y;
            this.dir = dir;
        }
    }
    private static int tc = 10;
    private static int[][] ladders;
    private static List<Pair> start = new ArrayList<>();

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringBuilder sb = new StringBuilder();
        StringTokenizer st;

        for (int t = 1; t <= tc; t++) {
            br.readLine();
            ladders = new int[100][100];
            visited = new boolean[100][100];
            start = new ArrayList<>();

            for (int i = 0; i < 100; i++) {
                st = new StringTokenizer(br.readLine());
                for (int j = 0; j < 100; j++) {
                    ladders[i][j] = Integer.parseInt(st.nextToken());
                    if (i == 0 && ladders[i][j] == 1) {
                        start.add(new Pair(i, j));
                    }
                }
            }

            sb.append("#").append(t).append(" ");
            for (int i = 0; i < start.size(); i++) {
                Pair cur = start.get(i);
                if (bfs(cur.x, cur.y)) {
                    sb.append(cur.y);
                }
            }
            sb.append("\n");
        }
        System.out.println(sb);
    }

    private static boolean bfs(int startX, int startY) {
        int curX = startX;
        int curY = startY;

        while (curX < 100) {
            if (curY > 0 && ladders[curX][curY - 1] == 1) {
                // 왼쪽으로 쭉 감
                while (curY > 0 && ladders[curX][curY - 1] == 1) {
                    curY--;
                }
            } else if (curY < 99 && ladders[curX][curY + 1] == 1) {
                // 오른쪽으로 쭉 감
                while (curY < 99 && ladders[curX][curY + 1] == 1) {
                    curY++;
                }
            }
            curX++; // 아래로 한 칸
        }

        return ladders[curX - 1][curY] == 2;
    }

}

코드 설명

  • start 리스트에 시작 위치를 저장합니다.
  • simulate(int startX, int startY)
    사다리타기 게임하는 함수
    • curX가 100이라는 것은 마지막 위치에 도달했다는 의미이므로 종료조건으로 선언해줍니다.
    • 왼쪽에 1이 있을 경우(if (curY > 0 & ladders[curX][curY - 1] == 1)
      • 왼쪽으로 끝까지 이동합니다.
    • 오른쪽에 1이 있을 경우(if (curY < 99 & ladders[curX][curY + 1] == 1)
      • 오른쪽으로 끝까지 이동합니다.
    • 아래로 한칸 이동합니다.
    • 현재 칸이 2(목표지점)에 도달했는지 확인합니다.
      return ladders[curX - 1][curY] == 2
제가 공부한 내용을 정리하는 블로그입니다.
아직 많이 부족하고 배울게 너무나도 많습니다. 틀린내용이 있으면 언제나 가감없이 말씀해주시면 감사하겠습니다😁
SWEA 1247 최적경로입니다.

포인트

집과 회사의 위치는 고정되어 있고, 중간에 방문해야 하는 고객들의 위치를 어떤 순서로 방문할지 결정하는 것이 핵심 문제입니다.
경로는 다음과 같은 형태로 구성됩니다:

회사 → 고객 1 → 고객 2 → ... → 고객 n → 집

이때, n명의 고객을 어떤 순서로 방문할지 결정하여 전체 경로의 맨해튼 거리 합이 최소가 되도록 해야 합니다.
고객들의 방문 순서를 정하는 모든 경우를 탐색하려면 순열을 고려해야 하며, 이는 시간복잡도 O(n!)의 완전탐색 문제로 볼 수 있습니다.

최악의 경우 n = 10일 때, 총 경우의 수는 10! = 3,628,800이며, 이는 Java 기준으로 일반적인 환경에서 20초 이내에 충분히 처리 가능한 수준입니다.
따라서, n이 10 이하라면 완전탐색 방식으로도 무리가 없습니다.

소스코드

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;

public class Q1247 {
    static class Pair {
        int x, y;

        public Pair(int x, int y) {
            this.x = x;
            this.y = y;
        }
    }

    private static int testCase, N, ans = Integer.MAX_VALUE;
    private static Pair company, house;
    private static Pair[] customers;
    private static boolean[] visited;

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        testCase = Integer.parseInt(br.readLine());

        StringBuilder sb = new StringBuilder();
        StringTokenizer st;
        for (int t = 1; t <= testCase; t++) {
            N = Integer.parseInt(br.readLine());
            st = new StringTokenizer(br.readLine());
            ans = Integer.MAX_VALUE;
            customers = new Pair[N];
            visited = new boolean[N];

            for (int i = 0; i < N + 2; i++) {
                if (i == 0) {
                    company = new Pair(Integer.parseInt(st.nextToken()), Integer.parseInt(st.nextToken()));
                } else if (i == 1) {
                    house = new Pair(Integer.parseInt(st.nextToken()), Integer.parseInt(st.nextToken()));
                } else {
                    customers[i - 2] = new Pair(Integer.parseInt(st.nextToken()), Integer.parseInt(st.nextToken()));
                }
            }

            dfs(new ArrayList<Integer>(), 0);

            sb.append("#").append(t).append(" ").append(ans);
            if (t != testCase) {
                sb.append("\n");
            }
        }
        System.out.println(sb);
    }

    private static void dfs(List<Integer> orders, int cnt) {
        if (cnt == N) {
            int sum = 0;
            sum = getSum(orders, sum);
            ans = Math.min(ans, sum);
            return;
        }

        for (int i = 0; i < N; i++) {
            if (visited[i]) continue;
            visited[i] = true;
            orders.add(i);

            dfs(orders, cnt + 1);

            orders.remove(orders.size() - 1);
            visited[i] = false;
        }
    }

    private static int getSum(List<Integer> orders, int sum) {
        Pair cur = company;

        for (int nextIdx : orders) {
            Pair next = customers[nextIdx];
            sum += cal(cur, next);
            cur = next;
        }

        sum += Math.abs(cur.x - house.x) + Math.abs(cur.y - house.y);
        return sum;
    }

    private static int cal(Pair cur, Pair next) {
        return Math.abs(cur.x - next.x) + Math.abs(cur.y - next.y);
    }
}

/**
3
5
0 0 100 100 70 40 30 10 10 5 90 70 50 20
6
88 81 85 80 19 22 31 15 27 29 30 10 20 26 5 14
10
39 9 97 61 35 93 62 64 96 39 36 36 9 59 59 96 61 7 64 43 43 58 1 36
*/

코드 설명

  • 집, 회사, 고객을 Pair 클래스로 초기화합니다.
  • dfs(List<Integer> orders, int cnt)
    고객의 방문 순서 = orders, cnt = 현재까지 고려한 고객의 수
    • 고객을 방문할 때마다 orders에 추가하고, visited 배열로 방문 여부 체크합니다.
    • 이후 dfs(orders, cnt+1)로 재귀 호출을 진행합니다.
    • 고객 수 cnt == n이면, 현재 순서대로 이동 거리 총합을 계산합니다
제가 공부한 내용을 정리하는 블로그입니다.
아직 많이 부족하고 배울게 너무나도 많습니다. 틀린내용이 있으면 언제나 가감없이 말씀해주시면 감사하겠습니다😁
SWEA 1249 보급로입니다.

포인트

문제가 여러 조건이 많은 것 같지만 배열의 숫자는 이동비용이라고 가정하면
결국 출발지로부터 도착지까지의 최소 비용을 구하는 문제입니다.

따라서 BFS로 문제를 풀면 가능합니다. BFS는 한 위치에 도달하기에 최소 경로가 보장되기 때문에
step이라는 배열을 통해 비용을 저장합니다.

소스코드


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.Queue;
import java.util.StringTokenizer;

public class Q1249 {
    static class Pair {
        int x, y;

        public Pair(int x, int y) {
            this.x = x;
            this.y = y;
        }
    }

    private static int testCase, N;
    private static int[][] map;
    private static boolean[][] visited;
    private static int[][] step;

    public static void main(String[] args) throws IOException {

        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        testCase = Integer.parseInt(br.readLine());

        StringBuilder sb = new StringBuilder();
        for (int t = 1; t <= testCase; t++) {
            N = Integer.parseInt(br.readLine());
            map = new int[N][N];
            visited = new boolean[N][N];
            step = new int[N][N];

            for (int i = 0; i < N; i++) {
                String line = br.readLine();
                Arrays.fill(step[i], Integer.MAX_VALUE);
                for (int j = 0; j < N; j++) {
                    map[i][j] = line.charAt(j) - '0';
                }
            }

            bfs();

            sb.append("#").append(t).append(" ").append(step[N - 1][N - 1]);
            if (t != testCase) {
                sb.append("\n");
            }
        }
        System.out.println(sb);
    }

    private static void bfs() {
        Queue<Pair> q = new LinkedList<>();
        q.add(new Pair(0, 0));
        step[0][0] = 0;
        visited[0][0] = true;

        int[] dx = {-1, 0, 1, 0};
        int[] dy = {0, 1, 0, -1};

        while (!q.isEmpty()) {
            Pair cur = q.poll();

            for (int idx = 0; idx < 4; idx++) {
                int nextX = cur.x + dx[idx];
                int nextY = cur.y + dy[idx];

                if (canGo(cur.x, cur.y, nextX, nextY)) {
                    step[nextX][nextY] = step[cur.x][cur.y] + map[nextX][nextY];
                    visited[nextX][nextY] = true;
                    q.add(new Pair(nextX, nextY));
                }
            }
        }
    }

    private static boolean canGo(int prevX, int prevY, int x, int y) {
        if(!inRange(x, y)) return false;
        if(step[x][y] <= step[prevX][prevY] + map[x][y]) return false;

        return true;
    }

    private static boolean inRange(int x, int y) {
        return 0 <= x && x < N && 0 <= y && y < N;
    }
}
/*
2
4
0100
1110
1011
1010
6
011001
010100
010011
101001
010101
111010
 */

코드 설명

  • inRange(int x, int y)
    x, y가 격자 내에 있는지 판단하는 함수
    • ROW와 COL을 기준으로 좌표가 16×16 격자 안에 있는지 확인합니다.
  • canGo(int x, int y)
    다음 칸을 갈 수 있는지 판단
    • 격자 범위를 벗어나지 않았고
    • 현재의 비용이 이미 저장된 비용보다 더 적은 경로라면
    • true를 반환
  • bfs() 함수
    • BFS 큐를 통해 너비 우선 탐색을 수행합니다.
    • 다음 위치 (nx, ny)가 갈 수 있는 위치이면 큐에 추가하고 방문 처리합니다
제가 공부한 내용을 정리하는 블로그입니다.
아직 많이 부족하고 배울게 너무나도 많습니다. 틀린내용이 있으면 언제나 가감없이 말씀해주시면 감사하겠습니다😁
SWEA 1218 괄호 짝짓기입니다.

포인트

닫힌 괄호 ), ], }, >는 항상 그에 대응하는 열린 괄호 (, [, {, <보다 뒤에 나와야 합니다.
따라서 문자열을 순회하면서 닫힌 괄호를 만날 때마다 최근에 열린 괄호와 짝이 맞는지 확인해주는 방식으로 유효성을 판단할 수 있습니다.

 

이를 위해 가장 적절한 자료구조는 LIFO(Last-In-First-Out) 구조인 스택(Stack) 입니다.

  • 열린 괄호는 스택에 저장하고,
  • 닫힌 괄호를 만났을 때 스택의 top과 매칭되는 열린 괄호인지 확인합니다.
  • 괄호가 올바르게 짝지어지지 않았거나, 스택이 비어있는 경우 → 올바르지 않은 문자열로 판단합니다.
  • (), {}, [], <>의 네 종류 괄호 짝을 모두 고려합니다.

소스코드

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;

public class Q1218 {
    private static int tc = 10, len;
    private static Set<Character> openSet = new HashSet<>();
    private static Map<Character, Character> closeMap = new HashMap<>();

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringBuilder sb = new StringBuilder();
        init();

        for (int t = 1; t <= tc; t++) {
            sb.append("#").append(t).append(" ");
            len = Integer.parseInt(br.readLine());
            Stack<Character> validation = new Stack<>();
            String line = br.readLine();
            boolean check = true;
            for (int i = 0; i < len; i++) {
                char cur = line.charAt(i);
                if (openSet.contains(cur)) {
                    validation.add(cur);
                } else {
                    char open = closeMap.get(cur);
                    if (open == validation.peek()) {
                        validation.pop();
                    } else {
                        check = false;
                        break;
                    }
                }
            }
            if (!validation.isEmpty()) {
                check = false;
            }
            sb.append(check ? 1 : 0).append("\n");
        }
        System.out.println(sb);
    }

    private static void init() {
        openSet.add('(');
        openSet.add('{');
        openSet.add('[');
        openSet.add('<');

        closeMap.put(')', '(');
        closeMap.put('}', '{');
        closeMap.put(']', '[');
        closeMap.put('>', '<');
    }
}

코드 설명

  • 전역변수
    • openSet: 여는 괄호 집합
    • closeMap: 닫는 괄호 -> 여는 괄호 대응 매핑
  • init() 함수
    • 열린 괄호들을 Set에 넣고, 닫힌 괄호의 대응 관계를 Map에 저장합니다.
    • 코드의 유연성과 가독성을 높이기 위해 사용된 초기 설정입니다.

main() 함수

Stack<Character> validation = new Stack<>();
boolean check = true;
  • 스택을 이용한 검사
    • validation 스택을 사용해 열린 괄호를 저장합니다.
    • check 변수는 문자열의 유효성을 판별하는 플래그입니다.
for (int i = 0; i < len; i++) {
    char cur = line.charAt(i);
    if (openSet.contains(cur)) {
        validation.add(cur);
    } else {
        char open = closeMap.get(cur);
        if (open == validation.peek()) {
            validation.pop();
        } else {
            check = false;
            break;
        }
    }
}
  • 문자 순회 및 처리
    • 열린 괄호 → 스택에 push
    • 닫힌 괄호 → 스택 top과 비교 후 pop 또는 실패 처리
    • 만약 스택이 비어있거나 짝이 맞지 않으면 실패로 처리
  • 반복이 끝났는데도 스택이 비어있지 않으면, 열린 괄호가 닫히지 않은 경우 -> 실패

+ Recent posts