Approach
Sorting and greedy selection
For Delete Duplicate Folders in System, the implementation first exposes a useful order, then scans that order while making locally justified choices.
- Choose the key that reveals the greedy or grouping structure.
- Sort the relevant records by that key.
- Scan in order, maintaining the invariant that makes each local choice safe.
Code notes
- 71 lines of Java from the credited upstream file 1948.java.
- The implementation visibly relies on sequence storage, hash lookup, ordered lookup.
- 7 loop blocks detected.
Complexity
Sorting is typically the dominant term unless the subsequent scan uses a more expensive nested operation.
Check the problem constraints before deciding whether this complexity will pass.
Use this to learn the idea, then write your own version.
1class TrieNode {2 public Map<String, TrieNode> children = new HashMap<>();3 public boolean deleted = false;4}5 6class Solution {7 public List<List<String>> deleteDuplicateFolder(List<List<String>> paths) {8 List<List<String>> ans = new ArrayList<>();9 Map<String, List<TrieNode>> subtreeToNodes = new HashMap<>();10 11 Collections.sort(paths,12 Comparator.<List<String>>comparingInt(List::size).thenComparing((a, b) -> {13 for (int i = 0; i < Math.min(a.size(), b.size()); ++i) {14 final int c = a.get(i).compareTo(b.get(i));15 if (c != 0)16 return c;17 }18 return 0;19 }));20 21 for (List<String> path : paths) {22 TrieNode node = root;23 for (final String s : path) {24 node.children.putIfAbsent(s, new TrieNode());25 node = node.children.get(s);26 }27 }28 29 buildSubtreeToRoots(root, subtreeToNodes);30 31 for (List<TrieNode> nodes : subtreeToNodes.values())32 if (nodes.size() > 1)33 for (TrieNode node : nodes)34 node.deleted = true;35 36 constructPath(root, new ArrayList<>(), ans);37 return ans;38 }39 40 private TrieNode root = new TrieNode();41 42 private StringBuilder buildSubtreeToRoots(TrieNode node,43 Map<String, List<TrieNode>> subtreeToNodes) {44 StringBuilder sb = new StringBuilder("(");45 for (final String s : node.children.keySet()) {46 TrieNode child = node.children.get(s);47 sb.append(s).append(buildSubtreeToRoots(child, subtreeToNodes));48 }49 sb.append(")");50 final String subtree = sb.toString();51 if (!subtree.equals("()")) {52 subtreeToNodes.putIfAbsent(subtree, new ArrayList<>());53 subtreeToNodes.get(subtree).add(node);54 }55 return sb;56 }57 58 private void constructPath(TrieNode node, List<String> path, List<List<String>> ans) {59 for (final String s : node.children.keySet()) {60 TrieNode child = node.children.get(s);61 if (!child.deleted) {62 path.add(s);63 constructPath(child, path, ans);64 path.remove(path.size() - 1);65 }66 }67 if (!path.isEmpty())68 ans.add(new ArrayList<>(path));69 }70}71