From b852cb11fc90557cf3aab5f52041e60bca90444e Mon Sep 17 00:00:00 2001 From: Valentyn Kolesnikov Date: Mon, 15 Jul 2024 19:10:20 +0300 Subject: [PATCH 1/3] Improved task 3213 --- .../Solution.java | 2 +- .../Solution.java | 203 ++++++------------ 2 files changed, 71 insertions(+), 134 deletions(-) diff --git a/src/main/java/g3201_3300/s3203_find_minimum_diameter_after_merging_two_trees/Solution.java b/src/main/java/g3201_3300/s3203_find_minimum_diameter_after_merging_two_trees/Solution.java index e91dc8578..2cbf2f1f2 100644 --- a/src/main/java/g3201_3300/s3203_find_minimum_diameter_after_merging_two_trees/Solution.java +++ b/src/main/java/g3201_3300/s3203_find_minimum_diameter_after_merging_two_trees/Solution.java @@ -1,6 +1,6 @@ package g3201_3300.s3203_find_minimum_diameter_after_merging_two_trees; -// #Hard #Tree #Graph #Depth_First_Search #Breadth_First_Search +// #Hard #Depth_First_Search #Breadth_First_Search #Tree #Graph // #2024_07_04_Time_29_ms_(99.83%)_Space_110.9_MB_(86.36%) import java.util.Arrays; diff --git a/src/main/java/g3201_3300/s3213_construct_string_with_minimum_cost/Solution.java b/src/main/java/g3201_3300/s3213_construct_string_with_minimum_cost/Solution.java index 0ca71417a..2412c818d 100644 --- a/src/main/java/g3201_3300/s3213_construct_string_with_minimum_cost/Solution.java +++ b/src/main/java/g3201_3300/s3213_construct_string_with_minimum_cost/Solution.java @@ -1,165 +1,102 @@ package g3201_3300.s3213_construct_string_with_minimum_cost; // #Hard #Array #String #Dynamic_Programming #Suffix_Array -// #2024_07_13_Time_1907_ms_(5.01%)_Space_100.9_MB_(5.09%) +// #2024_07_15_Time_261_ms_(88.55%)_Space_67.2_MB_(45.91%) -import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; public class Solution { - List buildKmpPrefix(String target) { - List w = new ArrayList<>(Collections.nCopies(target.length(), 0)); - int k = 0; - int i = 1; - while (i < target.length()) { - if (target.charAt(i) == target.charAt(k)) { - k++; - w.set(i, k); - i++; - } else { - if (k != 0) { - k = w.get(k - 1); - } else { - i++; - } - } + private static class ACAutomaton { + private static class Node { + private char key; + private Integer val = null; + private int len; + private final Node[] next = new Node[26]; + private Node suffix = null; + private Node output = null; + private Node parent = null; } - return w; - } - List> find(List prefix, String target, String w) { - List> result = new ArrayList<>(); - int m = target.length(); - int n = w.length(); - int i = 0; - int k = 0; - while (i < m) { - if (target.charAt(i) == w.charAt(k)) { - i++; - k++; + public Node build(String[] patterns, int[] values) { + Node root = new Node(); + root.suffix = root; + root.output = root; + for (int i = 0; i < patterns.length; i++) { + put(root, patterns[i], values[i]); } - if (k == n) { - result.add(Arrays.asList(i - k, i)); - k = prefix.get(k - 1); - } else if (i < m && target.charAt(i) != w.charAt(k)) { - if (k != 0) { - k = prefix.get(k - 1); + for (int i = 0; i < root.next.length; i++) { + if (root.next[i] == null) { + root.next[i] = root; } else { - i++; + root.next[i].suffix = root; } } + return root; } - return result; - } - public int minimumCost(String target, String[] words, int[] costs) { - List targetPrefix = buildKmpPrefix(target); - Node root = new Node(); - for (int j = 0; j < words.length; j++) { - String x = words[j]; - if (x.length() < 320) { - Node p = root; - for (int i = 0; i < x.length(); i++) { - char c = x.charAt(i); - p.children.putIfAbsent(c, new Node()); - p = p.children.get(c); - if (i == x.length() - 1) { - if (p.cost == null) { - p.cost = costs[j]; - } else { - p.cost = Math.min(costs[j], p.cost); - } - } + private void put(Node root, String s, int val) { + Node node = root; + for (char c : s.toCharArray()) { + if (node.next[c - 'a'] == null) { + node.next[c - 'a'] = new Node(); + node.next[c - 'a'].parent = node; + node.next[c - 'a'].key = c; } + node = node.next[c - 'a']; } - } - Map> dm = - getIntegerMapMap(target, words, costs, targetPrefix); - List d = new ArrayList<>(); - d.add(new NodeCostPair(root, 0)); - int[] dp = new int[target.length() + 1]; - Arrays.fill(dp, -1); - dp[0] = 0; - for (int i = 0; i < target.length(); i++) { - char x = target.charAt(i); - List q = new ArrayList<>(); - Integer t = null; - for (NodeCostPair pair : d) { - Node p = pair.node; - int cost = pair.cost; - if (p.children.containsKey(x)) { - Node w = p.children.get(x); - if (w.cost != null) { - t = t == null ? cost + w.cost : Math.min(t, cost + w.cost); - } - q.add(new NodeCostPair(w, cost)); - } + if (node.val == null || node.val > val) { + node.val = val; + node.len = s.length(); } - t = getInteger(dm, i, dp, t); - if (t != null) { - dp[i + 1] = t; - q.add(new NodeCostPair(root, t)); - } - d = q; } - return dp[target.length()]; - } - private Integer getInteger(Map> dm, int i, int[] dp, Integer t) { - Map qm = dm.getOrDefault(i + 1, Collections.emptyMap()); - for (Map.Entry entry : qm.entrySet()) { - int b = entry.getKey(); - if (dp[b] >= 0) { - t = t == null ? dp[b] + entry.getValue() : Math.min(t, dp[b] + entry.getValue()); + public Node getOutput(Node node) { + if (node.output == null) { + Node suffix = getSuffix(node); + node.output = suffix.val != null ? suffix : getOutput(suffix); } + return node.output; } - return t; - } - private Map> getIntegerMapMap( - String target, String[] words, int[] costs, List targetPrefix) { - Map> dm = new HashMap<>(); - for (int i = 0; i < words.length; i++) { - String word = words[i]; - if (word.length() >= 320) { - List> q = find(targetPrefix, target, word); - for (List pair : q) { - int b = pair.get(0); - int e = pair.get(1); - dm.putIfAbsent(e, new HashMap<>()); - Map qm = dm.get(e); - if (qm.containsKey(b)) { - qm.put(b, Math.min(qm.get(b), costs[i])); - } else { - qm.put(b, costs[i]); - } - } + private Node go(Node node, char c) { + if (node.next[c - 'a'] == null) { + node.next[c - 'a'] = go(getSuffix(node), c); } + return node.next[c - 'a']; } - return dm; - } - private static class Node { - Map children; - Integer cost; - - public Node() { - this.children = new HashMap<>(); - this.cost = null; + private Node getSuffix(Node node) { + if (node.suffix == null) { + node.suffix = go(getSuffix(node.parent), node.key); + if (node.suffix.val != null) { + node.output = node.suffix; + } else { + node.output = node.suffix.output; + } + } + return node.suffix; } } - private static class NodeCostPair { - Node node; - int cost; - - public NodeCostPair(Node node, int cost) { - this.node = node; - this.cost = cost; + public int minimumCost(String target, String[] words, int[] costs) { + ACAutomaton ac = new ACAutomaton(); + ACAutomaton.Node root = ac.build(words, costs); + int[] dp = new int[target.length() + 1]; + Arrays.fill(dp, Integer.MAX_VALUE / 2); + dp[0] = 0; + ACAutomaton.Node node = root; + for (int i = 1; i < dp.length; i++) { + if (node != null) { + node = ac.go(node, target.charAt(i - 1)); + } + for (ACAutomaton.Node temp = node; + temp != null && temp != root; + temp = ac.getOutput(temp)) { + if (temp.val != null && dp[i - temp.len] < Integer.MAX_VALUE / 2) { + dp[i] = Math.min(dp[i], dp[i - temp.len] + temp.val); + } + } } + return dp[dp.length - 1] >= Integer.MAX_VALUE / 2 ? -1 : dp[dp.length - 1]; } } From f74a38c99fffe2092df0d5755a90d0c04f732853 Mon Sep 17 00:00:00 2001 From: Valentyn Kolesnikov Date: Mon, 15 Jul 2024 19:14:35 +0300 Subject: [PATCH 2/3] Updated sonar plugin --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 30b1d0fbf..810017049 100644 --- a/build.gradle +++ b/build.gradle @@ -2,7 +2,7 @@ plugins { id 'java' id 'maven-publish' id 'com.diffplug.spotless' version '6.25.0' - id 'org.sonarqube' version '5.0.0.4638' + id 'org.sonarqube' version '5.1.0.4882' id 'jacoco' } From 2631fd921490747bef713902ff04bec7dd5a852d Mon Sep 17 00:00:00 2001 From: Valentyn Kolesnikov Date: Mon, 15 Jul 2024 19:21:11 +0300 Subject: [PATCH 3/3] Improved task --- .../s3213_construct_string_with_minimum_cost/Solution.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/java/g3201_3300/s3213_construct_string_with_minimum_cost/Solution.java b/src/main/java/g3201_3300/s3213_construct_string_with_minimum_cost/Solution.java index 2412c818d..50101c879 100644 --- a/src/main/java/g3201_3300/s3213_construct_string_with_minimum_cost/Solution.java +++ b/src/main/java/g3201_3300/s3213_construct_string_with_minimum_cost/Solution.java @@ -86,9 +86,7 @@ public int minimumCost(String target, String[] words, int[] costs) { dp[0] = 0; ACAutomaton.Node node = root; for (int i = 1; i < dp.length; i++) { - if (node != null) { - node = ac.go(node, target.charAt(i - 1)); - } + node = ac.go(node, target.charAt(i - 1)); for (ACAutomaton.Node temp = node; temp != null && temp != root; temp = ac.getOutput(temp)) {