今天是节后工作第一天,还是祝大家龙年吉祥万事如意,还有开工大吉!然后第一题和最后一题一样,我就只放最后一题的题解,跳过第一题了。

100229. Find the Length of the Longest Common Prefix

给你两个 正整数 数组 arr1 和 arr2 。

正整数的 前缀 是其 最左边 的一位或多位数字组成的整数。例如,123 是整数 12345 的前缀,而 234 不是 。

设若整数 c 是整数 a 和 b 的 公共前缀 ,那么 c 需要同时是 a 和 b 的前缀。例如,5655359 和 56554 有公共前缀 565 ,而 1223 和 43456 没有 公共前缀。

你需要找出属于 arr1 的整数 x 和属于 arr2 的整数 y 组成的所有数对 (x, y) 之中最长的公共前缀的长度。

返回所有数对之中最长公共前缀的长度。如果它们之间不存在公共前缀,则返回 0 。

测试样例:

输入:arr1 = [1,10,100], arr2 = [1000]

输出:3

解释:存在 3 个数对 (arr1[i], arr2[j]) :

  • (1, 1000) 的最长公共前缀是 1 。
  • (10, 1000) 的最长公共前缀是 10 。
  • (100, 1000) 的最长公共前缀是 100 。

最长的公共前缀是 100 ,长度为 3 。

解答:寻找频次最高的前缀,最容易计算的数据结构是Trie树。利用Trie树可以记录arr1所有数字,然后再遍历arr2寻找最长前缀。

class Solution {
    private class TrieNode {
        HashMap<Character, TrieNode> next;
        boolean isEnd;

        public TrieNode() {
            next = new HashMap<>();
            isEnd = false;
        }
    }

    private void addStr(TrieNode node, String w) {
        for (int i = 0; i < w.length(); ++i) {
            char c = w.charAt(i);
            if (!node.next.containsKey(c)) {
                node.next.put(c, new TrieNode());
            }
            node = node.next.get(c);
        }
        node.isEnd = true;
    }

    private int findLen(TrieNode node, String w) {
        int add = 0;
        for (int i = 0; i < w.length(); ++i) {
            char c = w.charAt(i);
            if (!node.next.containsKey(c)) {
                break;
            }
            node = node.next.get(c);
            ++add;
        }
        return add;
    }

    public int longestCommonPrefix(int[] arr1, int[] arr2) {
        TrieNode root = new TrieNode();
        for (int n : arr1) {
            addStr(root, String.valueOf(n));
        }

        int res = 0;
        for (int n : arr2) {
            String tmp = String.valueOf(n);
            res = Math.max(res, findLen(root, tmp));
        }
        return res;
    }
}

100217. Most Frequent Prime

给你一个大小为 m x n 、下标从 0 开始的二维矩阵 mat 。在每个单元格,你可以按以下方式生成数字:

  • 最多有 8 条路径可以选择:东,东南,南,西南,西,西北,北,东北。
  • 选择其中一条路径,沿着这个方向移动,并且将路径上的数字添加到正在形成的数字后面。
  • 注意,每一步都会生成数字,例如,如果路径上的数字是 1, 9, 1,那么在这个方向上会生成三个数字:1, 19, 191 。

返回在遍历矩阵所创建的所有数字中,出现频率最高的、大于 10的素数;如果不存在这样的素数,则返回 -1 。如果存在多个出现频率最高的素数,那么返回其中最大的那个。

注意:移动过程中不允许改变方向。

测试样例:

输入:mat = [[1,1],[9,9],[1,1]]

输出:19

解释:从单元格 (0,0) 出发,有 3 个可能的方向,这些方向上可以生成的大于 10 的数字有:

  • 东方向: [11], 东南方向: [19], 南方向: [19,191] 。
  • 从单元格 (0,1) 出发,所有可能方向上生成的大于 10 的数字有:[19,191,19,11] 。
  • 从单元格 (1,0) 出发,所有可能方向上生成的大于 10 的数字有:[99,91,91,91,91] 。
  • 从单元格 (1,1) 出发,所有可能方向上生成的大于 10 的数字有:[91,91,99,91,91] 。
  • 从单元格 (2,0) 出发,所有可能方向上生成的大于 10 的数字有:[11,19,191,19] 。
  • 从单元格 (2,1) 出发,所有可能方向上生成的大于 10 的数字有:[11,19,19,191] 。

在所有生成的数字中,出现频率最高的素数是 19 。

解答:这道题目有点Hard Code,就是各个位置强行遍历一下。需要增加的算法只有判断一个数是否是质数。因为怕数据量比较大(其实不大。。。),我加了一个HashSet来缓存所有遍历过的数字和它是否是质数的情况。

class Solution {
    private static final int[][] moves = {{0,1},{0,-1},{1,0},{1,1},{1,-1},{-1,0},{-1,1},{-1,-1}};
    private static Set<Integer> isPrime = new HashSet<>(), isMet = new HashSet<>();

    public int mostFrequentPrime(int[][] mat) {
        int m = mat.length, n = mat[0].length;
        HashMap<Integer, Integer> count = new HashMap<>();
        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                for (int[] mv : moves) {
                    int x = i, y = j;
                    int curNum = 0;
                    while (x >= 0 && x < m && y >= 0 && y < n) {
                        curNum = curNum * 10 + mat[x][y];
                        if (curNum >= 10 && isPrimeNum(curNum)) {
                            count.put(curNum, count.getOrDefault(curNum, 0) + 1);
                        }
                        x += mv[0];
                        y += mv[1];
                    }
                }
            }
        }
        int res = -1, max = 0;
        for (Map.Entry<Integer, Integer> entry : count.entrySet()) {
            if (entry.getValue() > max) {
                max = entry.getValue();
                res = entry.getKey();
            } else if (entry.getValue() == max) {
                res = Math.max(res, entry.getKey());
            }
        }
        return res;
    }

    private boolean isPrimeNum(int n) {
        if (isMet.contains(n)) {
            return isPrime.contains(n);
        } else {
            boolean res = isPrimeNumCal(n);
            isMet.add(n);
            if (res) {
                isPrime.add(n);
            }
            return res;
        }
    }

    private boolean isPrimeNumCal(int n) {
        for (int i = 2; i * i <= n; ++i) {
            if (n % i == 0) {
                return false;
            }
        }
        return true;
    }
}

100208. Count Prefix and Suffix Pairs II

给你一个下标从 0 开始的字符串数组 words 。

定义一个 布尔 函数 isPrefixAndSuffix ,它接受两个字符串参数 str1 和 str2 :

  • 当 str1 同时是 str2 的前缀(prefix)和后缀(suffix)时,isPrefixAndSuffix(str1, str2) 返回 true,否则返回 false。

例如,isPrefixAndSuffix("aba", "ababa") 返回 true,因为 "aba" 既是 "ababa" 的前缀,也是 "ababa" 的后缀,但是 isPrefixAndSuffix("abc", "abcd") 返回 false。

以整数形式,返回满足 i < j 且 isPrefixAndSuffix(words[i], words[j]) 为 true 的下标对 (i, j) 的 数量 。

测试样例:

输入:words = ["a","aba","ababa","aa"]

输出:4

解释:在本示例中,计数的下标对包括:

  • i = 0 且 j = 1 ,因为 isPrefixAndSuffix("a", "aba") 为 true 。
  • i = 0 且 j = 2 ,因为 isPrefixAndSuffix("a", "ababa") 为 true 。
  • i = 0 且 j = 3 ,因为 isPrefixAndSuffix("a", "aa") 为 true 。
  • i = 1 且 j = 2 ,因为 isPrefixAndSuffix("aba", "ababa") 为 true 。

因此,答案是 4 。

解答:这题和上周周赛其实一样,还是可以利用前缀哈希来解决。有一点需要注意,它的结果是long。我WA了好几次,最后发现用int型爆长度了。。。

class Solution {
    private static final int mod = 1_000_000_007;

    public long countPrefixSuffixPairs(String[] words) {
        HashMap<Long, Integer> set = new HashMap<>();
        long res = 0;
        for (String word : words) {
            int len = word.length();
            long left = 0, right = 0, mul = 1;
            for (int i = 0, j = len - 1; i < word.length(); ++i, --j) {
                left = (word.charAt(i) * mul + left) % mod;
                right = ((right * 331) + word.charAt(j)) % mod;
                if (left == right && set.containsKey(left)) {
                    res += set.get(left);
                }
                mul = (mul * 331) % mod;
            }
            set.put(left, set.getOrDefault(left,0) + 1);
        }
        return res;
    }
}

Leave a Reply

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