[Java] Union-find and Kruskal based solution with comments
java\nclass Solution {\n    public List<List<Integer>> findCriticalAndPseudoCriticalEdges(int n, int[][] edges) {\n        List<int[]> weights = new ArrayList<>
```java\nclass Solution {\n    public List<List<Integer>> findCriticalAndPseudoCriticalEdges(int n, int[][] edges) {\n        List<int[]> weights = new ArrayList<>();\n        for (int[] edge : edges) {\n            weights.add(edge);\n        }\n        Collections.sort(weights, (w1, w2) -> Integer.compare(w1[2], w2[2]));\n        \n        List<Integer> critical = new ArrayList<>();\n        List<Integer> pseudo = new ArrayList<>();\n        // Min cost of MST.\n        int minCost = costOfMST(n, weights, null, null);\n        for (int i = 0; i < edges.length; ++i) {\n            int[] edge = edges[i];\n            if (costOfMST(n, weights, null, edge) > minCost) {\n                // Without critical edge, cost increases.\n                critical.add(i);\n            } else if (costOfMST(n, weights, edge, null) == minCost) {\n                // Since edge is not critical, as long as it can be part of MST, it\'s pseudo.\n                pseudo.add(i);\n            }\n        }\n        return Arrays.asList(critical, pseudo);\n    }\n    \n    private int costOfMST(int n, List<int[]> edges, int[] required, int[] avoid) {\n        int cost = 0;\n        DSU dsu = new DSU(n);\n        if (required != null) {\n            dsu.union(required[0], required[1]);\n            cost += required[2];\n        }\n        for (int[] edge : edges) {\n            if (edge != avoid && dsu.union(edge[0], edge[1])) {\n                cost += edge[2];\n            }\n            if (dsu.getGroups() == 1) {\n                return cost;\n            }\n        }\n        return Integer.MAX_VALUE;\n    }\n    \n    static class DSU {\n        private int[] parents;\n        private int[] rank;\n        private int size;\n\n        public DSU(int size) {\n          this.size = size;\n          parents = new int[size];\n          rank = new int[size];\n          for (int i = 0; i < size; ++i) {\n            parents[i] = i;\n          }\n        }\n\n        public boolean union(int x, int y) {\n          int parentX = find(x);\n          int parentY = find(y);\n          if (parentX == parentY) {\n            return false;\n          }\n\n          if (rank[parentX] < rank[parentY]) {\n            parents[parentX] = parentY;\n          }\n          else {\n            parents[parentY] = parentX;\n            if (rank[parentX] == rank[parentY]) {\n              ++rank[parentX];\n            }\n          }\n\n          --size;\n          return true;\n        }\n\n        public int getGroups() {\n          return size;\n        }\n\n        public int find(int x) {\n          while (parents[x] != x) {\n            parents[x] = parents[parents[x]];\n            x = parents[x];\n          }\n\n          return parents[x];\n        }\n    }\n}\n```
[]