[atcoder]【LCR114] [

fishcanfly發表於2024-05-04

import java.util.*;

class Solution {
    public static void main(String[] args) {
        Solution solution = new Solution();
        String str = solution.alienOrder(new String[]{
                "wrt", "wrf", "er", "ett", "rftt"
        });
        System.out.println(str);
    }

    public String alienOrder(String[] words) {
        for (int i = 0; i < 26; i++) {
            children[i] = new ArrayList<>();
            parent[i] = new ArrayList<>();
        }
        int p = -1;
        for (int i = 0; i < words.length && valid; i++) {
            char ch = words[i].charAt(0);
            if (p != -1 && p != ch - 'a') {
                addEdge((char)(p+'a'), ch);
            } else {
                // do nothing since no parent
            }
            p = ch - 'a';
        }
        for (int i = 0; i < words.length && valid; i++) {
            build(words[i]);
        }
        String str = bfs();
        return str;
    }

    public String bfs() {
        if (!valid) {
            return "";
        }
        StringBuilder sb = new StringBuilder();
        boolean[] visited = new boolean[26];
        ArrayDeque<Integer> arrayDeque = new ArrayDeque<>();
        LinkedList<Integer> list = new LinkedList<>();
        for (int i = 0; i < 26; i++) {
            if (children[i].isEmpty() && dict[i]) {
                arrayDeque.add(i);
                visited[i] = true;
                list.addFirst(i);
            }
        }
        while (!arrayDeque.isEmpty()) {
            int curr = arrayDeque.poll();
            for (int p : parent[curr]) {
                if (!visited[p]) {
                    arrayDeque.add(p);
                    visited[p] = true;
                    list.addFirst(p);
                }
            }
        }
        boolean[] used = new boolean[26];
        while(!list.isEmpty()) {
            int curr = list.poll();
            sb.append((char)(curr+'a'));
            used[curr] = true;
        }
        for (int i = 0; i<26;i++){
            if(dict[i] && !used[i]) {
                sb.append((char)(i+'a'));
            }
        }
        return sb.toString();
    }

    public void build(String str) {
        TrieNode curr = dummy;
        for (int j = 0; j < str.length() && valid; j++) {
            char ch = str.charAt(j);
            curr.addChild(ch);
            curr = curr.getChild(ch);
            dict[ch - 'a'] = true;
        }
    }

    boolean[] dict = new boolean[26];
    TrieNode dummy = new TrieNode(' ');
    List<Integer>[] parent = new ArrayList[26];
    List<Integer>[] children = new ArrayList[26];

    /**
     * ch1 是ch2的祖先
     *
     * @param ch1
     * @param ch2
     * @return
     */
    boolean isAncestor(char ch1, char ch2) {
        boolean[] visited = new boolean[26];
        ArrayDeque<Integer> arrayDeque = new ArrayDeque<>();
        arrayDeque.add(ch1 - 'a');

        visited[ch1 - 'a'] = true;
        while (!arrayDeque.isEmpty()) {
            int curr = arrayDeque.poll();
            if (curr == ch2 - 'a') {
                return true;
            }
            for (int child : children[curr]) {
                if (!visited[child]) {
                    arrayDeque.add(child);
                    visited[child] = true;
                }
            }
        }
        return false;
    }

    boolean valid = true;

    public void addEdge(char parentCh, char ch){
        if (ch == parentCh) {
            // 祖先節點和子節點一樣,則不需要
        } else if (isAncestor(ch, parentCh)) {
            valid = false;
        }
        // 否則
        else if (isAncestor(parentCh, ch)) {
            // 關係已經存在, 忽略
        } else {
            // 加一個關係
            children[parentCh].add(ch - 'a');
            parent[ch - 'a'].add(parentCh - 'a');
        }
    }
    class TrieNode {
        char ch;
        TreeMap<Integer, TrieNode> map = new TreeMap<>();

        public void addChild(char ch) {
            TrieNode parentNode = map.lastEntry() != null ? map.lastEntry().getValue() : null;
            // add a trie node;
            TrieNode node = getChild(ch);
            if (node != null) {
                return;
            }
            node = new TrieNode(ch);
            map.put(ch - 'a', node);
            // 構建圖關係
            if (map.size() == 1) {
                //沒有關係,忽略
            } else {
                // 構建關係
                addEdge(parentNode.ch, ch);
            }
        }

        public TrieNode getChild(char ch) {
            return map.get(ch - 'a');
        }

        public TrieNode(char ch) {
            this.ch = ch;
            map = new TreeMap<>();
        }
    }

}