欢迎大家加QQ群:623375442,可以方便群里面交流。

3289. The Two Sneaky Numbers of Digitville

数字小镇 Digitville 中,存在一个数字列表 nums,其中包含从 0 到 n - 1 的整数。每个数字本应 只出现一次,然而,有 两个 顽皮的数字额外多出现了一次,使得列表变得比正常情况下更长。

为了恢复 Digitville 的和平,作为小镇中的名侦探,请你找出这两个顽皮的数字。

返回一个长度为 2 的数组,包含这两个数字(顺序任意)。

测试样例:

输入:nums = [0,1,1,0]

输出:[0,1]

解释:数字 0 和 1 分别在数组中出现了两次。

解答:直接利用HashSet来搜索出现多次的数字。

class Solution {
    public int[] getSneakyNumbers(int[] nums) {
        Set<Integer> set = new HashSet<>();
        int[] res = {-1,-1};
        int pos = 0;
        for (int n : nums) {
            if (set.contains(n)) {
                res[pos++] = n;
            } else {
                set.add(n);
            }
        }
        return res;
    }
}

3290. Maximum Multiplication Score

给你一个大小为 4 的整数数组 a 和一个大小 至少为 4 的整数数组 b。

你需要从数组 b 中选择四个下标 i0, i1, i2, 和 i3,并满足 i0 < i1 < i2 < i3。你的得分将是 a[0] b[i0] + a[1] b[i1] + a[2] b[i2] + a[3] b[i3] 的值。

返回你能够获得的 最大 得分。

测试样例:

输入: a = [3,2,5,6], b = [2,-6,4,-5,-3,2,-7]

输出:26

解释:选择下标 0, 1, 2 和 5。得分为 3 2 + 2 (-6) + 5 4 + 6 2 = 26。

解答:经典动态规划题目。

class Solution {
    public long maxScore(int[] a, int[] b) {
        long[] dp = new long[4];
        Arrays.fill(dp, Long.MIN_VALUE);
        long res = Long.MIN_VALUE;
        for (int i = 0; i < b.length; ++i) {
            long[] nextDP = new long[4];
            Arrays.fill(nextDP, Long.MIN_VALUE);
            for (int j = Math.min(3, i); j >= 0; --j) {
                long mul = (long) a[j];
                if (j == 0) {
                    nextDP[j] = Math.max(dp[j], mul * b[i]);
                } else if (dp[j - 1] != Long.MIN_VALUE) {
                    nextDP[j] = Math.max(dp[j], dp[j - 1] + mul * b[i]);
                }
            }
            res = Math.max(res, nextDP[3]);
            dp = nextDP;
        }
        return res;
    }
}

3292. Minimum Number of Valid Strings to Form Target II

给你一个字符串数组 words 和一个字符串 target。

如果字符串 x 是 words 中 任意 字符串的 前缀,则认为 x 是一个 有效 字符串。

现计划通过 连接 有效字符串形成 target ,请你计算并返回需要连接的 最少 字符串数量。如果无法通过这种方式形成 target,则返回 -1。

测试样例:

输入:words = ["abc","aaaaa","bcdef"], target = "aabcdabc"

输出:3

解释:target 字符串可以通过连接以下有效字符串形成:

  • words[1] 的长度为 2 的前缀,即 "aa"。
  • words[2] 的长度为 3 的前缀,即 "bcd"。
  • words[0] 的长度为 3 的前缀,即 "abc"。

解答:利用AC自动机。前缀越短,需要的匹配数量一定越小。

class Solution {
    public static final int INF = Integer.MAX_VALUE / 2;

    public int minValidStrings(String[] words, String target) {
        int[] dp = new ACAutomaton(words).minCost(target);
        int n = target.length();
        return dp[n] == INF ? -1 : dp[n];
    }

    private class ACAutomaton {
        Node root = new Node();

        ACAutomaton(String[] words) {
            for (String word : words) {
                add(word);
            }
            buildLinks();
        }

        public int[] minCost(String target) {
            int n = target.length();
            int[] dp = new int[n + 1];
            Arrays.fill(dp, INF);
            dp[0] = 0;
            updateDp(target, dp);
            return dp;
        }

        private void add(String word) {
            Node node = root;
            for (int i = 0; i < word.length(); i++) {
                int index = word.charAt(i) - 'a';
                if (node.next[index] == null) {
                    node.next[index] = new Node();
                }
                node = node.next[index];
                node.length = i + 1;
            }
        }

        private void buildLinks() {
            Queue<Node> queue = new ArrayDeque<>();
            for (Node node : root.next) {
                if (node != null) {
                    node.suffix = root;
                    queue.offer(node);
                }
            }
            while (!queue.isEmpty()) {
                Node node = queue.poll();
                for (int i = 0; i < 26; i++) {
                    Node next = node.next[i];
                    if (next != null) {
                        Node suffix = node.suffix;
                        while (next.suffix == null) {
                            if (suffix.next[i] != null) {
                                next.suffix = suffix.next[i];
                            } else if (suffix == root) {
                                next.suffix = root;
                            } else {
                                suffix = suffix.suffix;
                            }
                        }
                        queue.offer(next);
                    }
                }
            }
        }

        private void updateDp(String target, int[] dp) {
            Node node = root;
            for (int i = 1; i <= target.length(); i++) {
                int index = target.charAt(i - 1) - 'a';
                while (node != root && node.next[index] == null) {
                    node = node.suffix;
                }
                if (node.next[index] != null) {
                    node = node.next[index];
                }
                if (node.length != -1) {
                    dp[i] = Math.min(dp[i], dp[i - node.length] + 1);
                }
            }
        }

        private class Node {
            Node[] next = new Node[26];
            Node suffix;
            int length = -1;
        }
    }
}

Leave a Reply

Your email address will not be published. Required fields are marked *