leetcode update

This commit is contained in:
gameloader 2024-09-25 11:05:33 +08:00
parent 0149d9ca67
commit 57ebd283c8

View File

@ -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;i<TREESIZE;++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){
if (node->children[c-'0'] == nullptr){
node->children[c-'0'] = new TrieNode();
}
node = node->children[c-'0'];
}
node->isEndOfWord = true;
}
~Trie() {
function<void(TrieNode*)> 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<int>& arr1, vector<int>& 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;i<TREESIZE;i++){
if (root1->children[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。这样对于有包含关系的前缀就会产生大量重复同时没能充分利用前缀自身自带的字符的先后关系字符串aba是在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<void(TrieNode*)> 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<int> sumPrefixScores(vector<string>& words) {
Trie *trie = new Trie();
for (string word : words){
trie->insert(word);
}
vector<int> result;
for (string word : words){
result.push_back(trie->count(word));
}
return result;
}
};
```