From 57ebd283c8aabc671bde10fdd1f8b2371a62aa13 Mon Sep 17 00:00:00 2001 From: gameloader Date: Wed, 25 Sep 2024 11:05:33 +0800 Subject: [PATCH] leetcode update --- content/posts/leetcode.md | 204 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 204 insertions(+) diff --git a/content/posts/leetcode.md b/content/posts/leetcode.md index 053d711..1646780 100644 --- a/content/posts/leetcode.md +++ b/content/posts/leetcode.md @@ -13899,3 +13899,207 @@ public: }; ``` + +## day210 2024-09-24 + +### 3043. Find the Length of the Longest Common Prefix + +You are given two arrays with positive integers arr1 and arr2. + +A prefix of a positive integer is an integer formed by one or more of its digits, starting from its leftmost digit. For example, 123 is a prefix of the integer 12345, while 234 is not. + +A common prefix of two integers a and b is an integer c, such that c is a prefix of both a and b. For example, 5655359 and 56554 have a common prefix 565 while 1223 and 43456 do not have a common prefix. + +You need to find the length of the longest common prefix between all pairs of integers (x, y) such that x belongs to arr1 and y belongs to arr2. + +Return the length of the longest common prefix among all pairs. If no common prefix exists among them, return 0. + +![0924WdYUOX86qpiT](https://testingcf.jsdelivr.net/gh/game-loader/picbase@master/uPic/0924WdYUOX86qpiT.png) + +### 题解 + +题目中的数组要求求最长公共前缀,考虑到每个数组中的不同数字之间也可能存在公共前缀,为了避免对字符串进行重复遍历,可以使用字典树。字典树充分利用了数字每一位的信息,非常适用于类似本题目的求前缀等场景下,还有一道经典题目是求数组中任意两个数字的最大异或和,也可以使用字典树求解,利用异或运算异或两次后会回到数字本身的特性,用数字的二进制形式构造字典树,充分利用每个二进制位的信息,通过贪心尽量将每一位置为1,最终找到最大异或和,可参考[P4551 最长异或路径](https://www.luogu.com.cn/problem/P4551) + +本题在对两个数组构建好两棵字典树后,对字典树同时进行dfs,依次选取每一层中相同的字符对应的子节点进行遍历,直到在某一层无法找到共同字符为止。用一个变量保存遍历到的树的最大深度即为最长公共前缀的长度。 + +### 代码 + +```cpp +#pragma GCC optimize("O3", "unroll-loops") + +const int TREESIZE = 10; + +struct TrieNode{ + TrieNode *children[TREESIZE]; + bool isEndOfWord; + + TrieNode(): isEndOfWord(false){ + for (int i = 0;ichildren[c-'0'] == nullptr){ + node->children[c-'0'] = new TrieNode(); + } + node = node->children[c-'0']; + } + node->isEndOfWord = true; + } + + ~Trie() { + function deleteTrie = [&](TrieNode* node) { + if(node == nullptr) return; + for(int i = 0; i < TREESIZE; ++i){ + if(node->children[i] != nullptr){ + deleteTrie(node->children[i]); + } + } + delete node; + }; + deleteTrie(root); + }; + +}; + +class Solution { +public: + int longestCommonPrefix(vector& arr1, vector& arr2) { + ios::sync_with_stdio(false); + Trie *trie1 = new Trie(); + for (int num : arr1){ + string numstr = to_string(num); + trie1->insert(numstr); + } + Trie *trie2 = new Trie(); + for (int num : arr2){ + string numstr = to_string(num); + trie2->insert(numstr); + } + int result = 0; + dfs(trie1->root, trie2->root, 0, result); + return result; + + } + + void dfs(TrieNode* root1,TrieNode* root2, int depth, int& result){ + result = max(result, depth); + for(int i=0;ichildren[i] != nullptr && root2->children[i] != nullptr){ + cout<< i; + dfs(root1->children[i],root2->children[i],depth+1,result); + } + } + } +}; +``` + +## day211 2024-09-25 + +### 2416. Sum of Prefix Scores of strings + +You are given an array words of size n consisting of non-empty strings. + +We define the score of a string word as the number of strings words[i] such that word is a prefix of words[i]. + +For example, if words = ["a", "ab", "abc", "cab"], then the score of "ab" is 2, since "ab" is a prefix of both "ab" and "abc". +Return an array answer of size n where answer[i] is the sum of scores of every non-empty prefix of words[i]. + +Note that a string is considered as a prefix of itself. + +![0925UvJwkizQjyZA](https://testingcf.jsdelivr.net/gh/game-loader/picbase@master/uPic/0925UvJwkizQjyZA.png) + +### 题解 + +本题是一道难题,但像这种要多次计算字符串前缀的问题我们已经熟悉了,为了避免重复遍历字符串可以使用字典树trie。在这个问题上思考一下为什么用字典树更好,如果我们用map将某个前缀作为key,其出现的次数作为value。这样对于有包含关系的前缀就会产生大量重复,同时没能充分利用前缀自身自带的字符的先后关系(字符串ab,a是在b前面且与b紧密相邻的,用字典树则将ab相邻和a在b前面这两种字符关系都表示了出来)。 + +熟悉字典树后,本题只需对每个字符串构建字典树,对字典树的节点做一些修改,节点中加入表示被访问到次数的count变量,无需记录节点是否为单词的结尾。构建好后对每个字符串,访问字典树,并将路径上所有节点的count相加即得最终的sum。 + +### 代码 + +```cpp +const int ALPHABET_SIZE = 26; + +struct TrieNode { + TrieNode* children[ALPHABET_SIZE]; + int count; + + TrieNode() : count(0) { + for(int i = 0; i < ALPHABET_SIZE; ++i){ + children[i] = nullptr; + } + } +}; + + +class Trie { +public: + TrieNode* root; + + Trie() { root = new TrieNode(); } + + void insert(const string &word) { + TrieNode* node = root; + for(char c : word){ + int index = c - 'a'; + if(index < 0 || index >= ALPHABET_SIZE){ + continue; + } + if(node->children[index] == nullptr){ + node->children[index] = new TrieNode(); + } + node = node->children[index]; + node->count++; + } + } + + int count(const string &word){ + int ret = 0; + TrieNode* node = root; + for(char c : word){ + int index = c - 'a'; + node = node->children[index]; + ret += node->count; + } + return ret; + } + + ~Trie() { + function deleteTrie = [&](TrieNode* node) { + if(node == nullptr) return; + for(int i = 0; i < ALPHABET_SIZE; ++i){ + if(node->children[i] != nullptr){ + deleteTrie(node->children[i]); + } + } + delete node; + }; + deleteTrie(root); + } +}; + + +class Solution { +public: + vector sumPrefixScores(vector& words) { + Trie *trie = new Trie(); + for (string word : words){ + trie->insert(word); + } + vector result; + for (string word : words){ + result.push_back(trie->count(word)); + } + return result; + } +}; +```