具有长度为 K 的公共前缀的字符串的最大数量

data structurec++programming

在这个问题中,我们需要计算具有长度为 K 的公共前缀的最大字符串数量。我们可以从所有字符串中取出长度为 K 的前缀,并使用 map 数据结构计算相似前缀的最大数量。此外,我们也可以使用 Trie 数据结构来解决这个问题。

问题描述- 我们给出了一个包含多个字符串的 strs[] 数组。我们需要计算包含长度为 K 的公共前缀的字符串的最大数量。

示例

输入

strs = {"tutorialspoint", "tut", "abcd", "tumn", "tutorial", "PQR", "ttus", "tuto"};
 K = 3;

输出

4

说明- 这 4 个字符串包含长度为 3 的 'tut' 前缀。

输入

strs = {"tutorialspoint", "tut", "abcd", "tumn", "tutorial", "PQR", "ttus", "tuto"};
K = 8;

输出

2

解释- 仅有的两个字符串包含相同的长度为 8 的前缀,即 'tutorial'。

输入

strs = {"tutorialspoint", "tut", "abcd", "tumn", "tutorial", "PQR", "ttus", "tuto"};
K = 8;

输出

1

解释- 数组不包含长度为 2 的公共前缀的字符串。因此,我们可以打印 1。

方法 1

在此方法中,我们将使用 map 数据结构来计算每个子字符串中长度为 K 的前缀的频率。最后,我们取频率最高的前缀显示在输出中。

算法

步骤 1 - 将 'ans' 初始化为 0,以存储具有公共前缀的最大字符串数量。另外,定义"pref"映射来存储字符串前缀的频率。

步骤 2 - 开始遍历字符串。

步骤 3 - 从 0 开始取长度为 K 的子字符串,并将其存储到"temp"字符串中。

步骤 4 - 在映射中将"temp"的频率加 1。

步骤 5 - 根据"ans"和"temp"字符串的频率获取最大答案。

步骤 6 - 最后,返回"ans"值。

示例

#include <bits/stdc++.h>
using namespace std;

int getMaxStrs(vector<string> strs, int K) {
   int ans = 0;
   // 映射以存储长度为 K 的前缀
   map<string, int> pref;
   // 遍历字符串
   for (int p = 0; p < strs.size(); p++) {
        // 取长度为 K 的子串
        string temp = strs[p].substr(0, K);
        // 将前缀插入到映射中
        pref[temp]++;
        // 获取最大答案
        ans = max(ans, pref[temp]);
   }
   return ans;
}
int main() {
   vector<string> strs = {"tutorialspoint", "tut", "abcd", "tumn", "tutorial", "PQR", "ttus", "tuto"};
   int K = 3;
   cout << "具有长度为 K 的公共前缀的字符串的数量是 " << getMaxStrs(strs, K);
   return 0;
}

输出

具有长度为 K 的公共前缀的字符串的数量是 4

时间复杂度 - 遍历字符串为 O(N)。

空间复杂度 - 将前缀的频率存储在映射中为 O(N)。

方法 2

在此方法中,我们将使用 trie 数据结构来查找具有公共前缀的字符串的最大数量。我们将所有字符串的前缀插入 trie 中,并检查其是否出现次数最多。

算法

步骤 1 - 初始化 trie 的节点,该节点包含长度为 26 的数组,用于指向当前节点中的每个字母字符,并将 'cnt' 变量初始化为 0,表示公共前缀的数量。

步骤 2 - 开始遍历数组中的每个字符串,并执行 insertNode() 函数将字符串长度为 K 的前缀插入 trie。另外,传递"ans"变量作为引用,以存储具有公共前缀的最大字符串数量。

步骤 3- 在 insertNode() 函数中,使用"head"节点初始化"temp"节点,并遍历字符串以将其前缀插入到 Trie 中。

步骤 4 - 使用 toLower() 方法将字符转换为小写。

步骤 5 - 如果 temp 节点的"chars"数组 (ch - 'a') 索引为空,则将新节点赋给它。

步骤 6 - 增加 temp->chars[ch - 'a'] 节点的"cnt"。

步骤 7 - 如果 p + 1 等于 K,则我们将长度为 K 的前缀插入到 Trie 中。因此,使用 'ans' 和 temp->chars[ch - 'a']->cnt 中的最大值更新 'ans',并跳出循环。

步骤 8 - 将临时节点移动到下一个节点。

步骤 9 - 最后,打印 'ans' 的值。

示例

#include <bits/stdc++.h>
using namespace std;

struct Node {
   Node *chars[26];
   int cnt = 0;
};
Node* head;
void insertNode(string &str, int K, int &ans) {
    // 临时节点
    Node *temp = head;
    // 遍历字符串字符
   for (int p = 0; p < str.size(); p++) {
      // 将字符转换为小写
      char ch = tolower(str[p]);
      // 如果当前字符对应的节点不存在,则初始化该节点
      if (temp->chars[ch - 'a'] == NULL) {
         temp->chars[ch - 'a'] = new Node();
      }
      // 增加计数以增加前缀的长度
      temp->chars[ch - 'a']->cnt++;
      // 如果 p + 1 等于 K,则取最大结果并跳出循环。
      if (p + 1 == K) {
         ans = max(ans, temp->chars[ch - 'a']->cnt);
         break;
      }
      // 转到下一个指针
      temp = temp->chars[ch - 'a'];
   }
}
int main() {
    vector<string> strs = {"tutorialspoint", "tut", "abcd", "tumn", "tutorial", "PQR", "ttus", "tuto"};
    int K = 3;
    int ans = 0;
    // 节点初始化
    head = new Node();
    // 将所有字符串插入到 Trie 字典中
    for (auto str : strs) {
      insertNode(str, K, ans);
    }
    cout << "具有长度为 K 的公共前缀的字符串的数量是 " << ans;
    return 0;
}

输出

具有长度为 K 的公共前缀的字符串的数量是 4

时间复杂度 - O(N*K),其中 N 为数组长度,K 为前缀长度。

空间复杂度 - O(N*K),将所有字符串存储在 Trie 中。

第一种方法更高效,也更易于初学者理解。第二种方法可能比较复杂,但学习 Trie 数据结构的概念是必要的。


相关文章