카테고리 없음

백준 14426, 5052 (Trie)

nownow 2025. 2. 27. 17:28

문자열의 순서를 고려해서 접두사인지 판별할때 활용할 수 있는 Trie

 

https://www.acmicpc.net/problem/14426

루트 노드를 기준으로 전개해나가고 각 노드에서 여러개의 갈래가 생길 수 있으므로

ArrayList로 노드를 연결시켜준다.

ArrayList대신 HashMap을 사용해도 가능.

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

class Main {
    static class node {
        char ch;
        ArrayList<node> nodes = new ArrayList<>();
    }

    static node root = new node();
    static int n, m;
    static int result=0;

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String str = br.readLine();
        StringTokenizer token = new StringTokenizer(str);
        n = Integer.parseInt(token.nextToken());
        m = Integer.parseInt(token.nextToken());
        for (int i = 0; i < n; i++) {
            str = br.readLine();
            add(str);
        }
        //test();
        for(int i=0;i<m;i++){
            str=br.readLine();
            result+=count(str);
        }
        System.out.println(result);
    }
    static int count(String str){
        int len = str.length();
        node temp = root;
        for (int i = 0; i < len; i++) {
            char alphabet = str.charAt(i);
            boolean newWay = true;
            for (node node : temp.nodes) {
                if (node.ch == alphabet) { //갈길이 있을경우
                    temp = node;
                    newWay = false;
                    break;
                }
            }
            if(newWay) {
                return 0;
            }
        }
        return 1;
    }
    static void test(){
        for(node node : root.nodes){
            System.out.println(node.ch);
        }
    }

    static void add(String str) {
        int len = str.length();
        node temp = root;
        for (int i = 0; i < len; i++) {
            char alphabet = str.charAt(i);
            boolean newWay = true;
            for (node node : temp.nodes) {
                if (node.ch == alphabet) { //갈길이 있을경우
                    temp = node;
                    newWay = false;
                    break;
                }
            }
            if(newWay) {
                node addedNode = new node();
                addedNode.ch=alphabet;
                temp.nodes.add(addedNode);
                temp=addedNode;
            }
        }
    }
}

/*
트라이
루트에서부터 26개의 갈 길을 두고 전개해나감
n개를 그렇게 세팅해두고
m개에서는 갈길이 없으면 멈추고 끝까지 나아가면 결과에 +1
 */

https://www.acmicpc.net/problem/5052

예제 입력에서

3
911
97625999
91125426

이미 입력된 전화번호의 종료 지점까지 동일한 케이스가 입력될 경우 접미사로 취급된다

해당 케이스만 고려해서 하면

911과 91125426의 순서가 바뀐 케이스를 잡을 수 없다.

한 케이스를 검증할 때, 그 케이스의 마지막 숫자를 확인하는데 이미 입력된 케이스의 Trie를 따라왔다면

그 케이스가 이미 있는 케이스의 접미사라고 취급하여 이 경우도 판별해주어야 한다.

 

대안

정렬을 통해 길이가 짧은 케이스 먼저 검증을 시도할 수도 있다.

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

class Main {

    static class node{
        char num;
        ArrayList<node> arr = new ArrayList<>();
        boolean finishLine;

    }
    static node root = new node();

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int testCase = Integer.parseInt(br.readLine());
        for(int i=0;i<testCase;i++){
            int numCount = Integer.parseInt(br.readLine());
            boolean flag=false;
            for(int j=0;j<numCount;j++){
                String str = br.readLine();
                if(!add(str)){
                    flag=true;
                }
            }
            if(flag){
                System.out.println("NO");
            }
            else{
                System.out.println("YES");
            }

            root=new node();
        }
    }
    static boolean add(String str){
        node temp = root;
        int len = str.length();
        for(int i=0;i<len;i++){
            boolean lastFlag = false;
            boolean moveFlag = false;
            if(i==len-1) lastFlag=true;
            char idxNum = str.charAt(i);
            for(node node : temp.arr){
                if(node.num==idxNum){ // 같은게 있다면
                    moveFlag=true;
                    temp=node;
                    if(temp.finishLine){
                        return false;
                    }
                    if(i==len-1){
                        return false;
                    }
                }
            }
            if(!moveFlag){
                node addedNode = new node();
                if(lastFlag){
                    addedNode.finishLine = true;
                }
                addedNode.num=idxNum;
                temp.arr.add(addedNode);
                temp=addedNode;
            }

        }
        return true;
    }
}

/*
트라이
이미 있는 트라이의 종료지점을 통과해선 안된다. 그럼 아예 STOP
or
내가 마지막인데 이미 있는곳을 왔다

1
3
91125426
911
97625999
 */

 

//HashMap을 사용하고 정렬처리한 코드


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

class Main {

    static class node {
        char num;
        //ArrayList<node> arr = new ArrayList<>();
        HashMap<Character, node> arr = new HashMap<>();
        boolean finishLine;

    }

    static node root = new node();
    static ArrayList<String> stringArr = new ArrayList<>();

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int testCase = Integer.parseInt(br.readLine());
        for (int i = 0; i < testCase; i++) {
            int numCount = Integer.parseInt(br.readLine());
            boolean flag = false;
            for (int j = 0; j < numCount; j++) {
                String str = br.readLine();
                stringArr.add(str);
            }
            Collections.sort(stringArr);
            for(String tempstr : stringArr){
                if (!add(tempstr)) {
                    flag = true;
                }
            }


            if (flag) {
                System.out.println("NO");
            } else {
                System.out.println("YES");
            }

            root = new node();
            stringArr = new ArrayList<>();
        }
    }

    static boolean add(String str) {
        node temp = root;
        int len = str.length();
        for (int i = 0; i < len; i++) {
            boolean lastFlag = false;
            boolean moveFlag = false;
            if (i == len - 1) lastFlag = true;
            char idxNum = str.charAt(i);
            //for(node node : temp.arr){
            node node = temp.arr.getOrDefault(idxNum,null);
            if (node!=null) { // 같은게 있다면
                moveFlag = true;
                temp = node;
                if (temp.finishLine) {
                    return false;
                }
//                if (i == len - 1) {
//                    return false;
//                }
            }
            //}
            if (!moveFlag) {
                node addedNode = new node();
                if (lastFlag) {
                    addedNode.finishLine = true;
                }
                addedNode.num = idxNum;
                temp.arr.put(idxNum,addedNode);
                temp = addedNode;
            }

        }
        return true;
    }
}

/*
트라이
이미 있는 트라이의 종료지점을 통과해선 안된다. 그럼 아예 STOP
or
내가 마지막인데 이미 있는곳을 왔다

1
3
91125426
911
97625999
 */

최하단 먼저 작성된 코드

중간 HashMap을 사용하되 정렬하지 않고 if문으로 검사한 코

최상단 아래쪽에 작성되어있는 코드