至少包含前K个字母一次的子串计数


在这个问题中,我们需要计算包含至少一个所有K个字符的子串。

在这里,我们将使用两种不同的方法来解决这个问题。第一种方法获取给定字符串的所有子串,检查子串是否包含所有K个字符,并计算包含所有K个字符的子串。

第二种方法使用滑动窗口技术来解决这个问题。

问题陈述 - 我们给定一个包含N个字符的字符串alpha。此外,我们还给定K,表示包含多个仅前K个字母字符的字符串。我们需要计算包含所有K个字符至少出现一次的子串总数。

示例

输入

alpha = "abcdda", K = 4;

输出

4

解释 - 包含所有4个字符的子串是'abcd','abcdd','abcdda'和'bcdda'。

输入

alpha = "abc", K = 5

输出

0

解释 - 给定字符串中没有包含所有5个字符的子串。

输入

alpha = "ccbba"; K = 3;

输出

2

解释 - 字符串'ccbba'和'cbba'包含所有3个字符。

方法1

在这种方法中,我们将遍历字符串以获取所有子串并将它们存储在列表中。之后,我们将计算列表中包含所有K个字符至少一次的字符串的数量。

算法

步骤1 - 初始化'subStr'列表以存储所有子串。

步骤2 - 开始遍历字符串。此外,使用嵌套循环从1到字符串大小 - p进行迭代。

步骤3 - 使用substr()方法从第p个索引获取子串,长度等于q。并将子串推入'subStr'列表。

步骤4 - 将'result'初始化为0,以存储有效子串的计数。

步骤5 - 开始遍历子串列表,并定义'freq'映射以存储当前字符串中字符的频率。还将'chars'初始化为0,以计算字符串中不同的字符。

步骤6 - 开始遍历当前字符串。如果映射中字符的频率为0,则更新频率并将'chars'值加1。

步骤7 - 如果chars的值等于K,则将'result'加1。

步骤8 - 返回result值。

示例

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

int numberOfSubstrings(string alpha, int K) {
   // Finding all substrings of the alpha
   vector<string> subStr;
   for (int p = 0; p < alpha.size(); p++) {
      for (int q = 1; q <= alpha.size() - p; q++) {
         // Get substring from p to q
         subStr.push_back(alpha.substr(p, q));
      }
   }
   // Counting the number of substrings containing all K characters
   int result = 0;
   for (int p = 0; p < subStr.size(); p++) {
      // To store the frequency of characters in the current substring
      map<char, int> freq;
      // To store the totally different characters
      int chars = 0;
      // Traverse substring
      for (int q = 0; q < subStr[p].size(); q++) {
         // If a character does not exist in the map, increment chars
         if (freq[subStr[p][q]] == 0) {
            freq[subStr[p][q]]++;
            chars++;
         }
      }
      // If different chars are the same as K, the string is valid.
      if (chars == K) {
         result++;
      }
   }
   return result;
}
int main() {
   string alpha = "abcdda";
   int K = 4;
   cout << "The number of substrings containing all K characters at least once is " << numberOfSubstrings(alpha, K);
   return 0;
}

输出

The number of substrings containing all K characters at least once is 4

时间复杂度 - O(N*N*M),其中O(N*N)用于获取所有子串,O(M)用于遍历字符串。

空间复杂度 - O(N*N)用于存储所有子串。

方法2

在这种方法中,我们将使用滑动窗口技术来计算包含所有K个字符至少一次的子串的数量。

算法

步骤1 - 初始化'freq'映射以存储字符频率,'left'和'right'指针为0,表示滑动窗口指针,'len'为字符串长度,'cnt'为0,用于存储字符串计数。

步骤2 - 直到'right'小于字符串长度,进行迭代。

步骤3 - 为映射中'right'索引处的字符增加字符频率。

步骤4 - 如果映射的大小等于K,则表示我们得到了包含所有K个字符的子串。因此,请按照以下步骤操作。

步骤4.1 - 直到映射的大小等于K,进行迭代。

步骤4.2 - 将'len - right'添加到'cnt'。

步骤4.3 - 要从当前窗口中删除左字符,请减少映射中其频率。如果映射中字符的频率为0,则从映射中删除该字符。

步骤4.4 - 在嵌套循环中递增'left'指针。

步骤4.5 - 在主循环中递增'right'指针。

步骤5 - 否则,递增'right'指针值。

步骤6 - 返回'cnt'值。

示例

让我们通过示例输入了解滑动窗口技术如何解决问题。

输入 - 'abcdaabc',K = 4

  • 第一个窗口将是'abcd',包含所有4个字符。因此,我们可以说(0, 3),(0, 4),(0, 5),(0, 6)和(0, 7)所有子串都包含所有K个字符。

  • 之后,从1到4的下一个窗口包含所有字符。因此,(1, 4),(1,5),(1, 6)和(1, 7)所有子串都至少包含一次所有K个字符。

  • 通过这种方式,我们可以计算每个有效窗口的子串数量。

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

int numberOfSubstrings(string alpha, int K) {
   // For storing the frequency of characters
   unordered_map<char, int> freq;
   int left = 0, right = 0, len = alpha.size(), cnt = 0;
   // Traveres the string
   while (right < len) {
     // Update character frequency
     freq[alpha[right]]++;
     // If the size of the map contains all K characters
     if (freq.size() == K) {
       // Traverse the map until the map size is k
       while (freq.size() == K) {
         // Add all valid substrings.
         // If (left, right) contains all K characters, (left, right + 1), (left + right + 2), ...  also contains.
         cnt += len - right;
         // Update character frequency
         freq[alpha[left]]--;
         // Remove the character if its frequency is 0.
         if (freq[alpha[left]] == 0)
            freq.erase(alpha[left]);
         // Move to the next character from left
         left++;
       }
       // Increment the right pointer.
       right++;
     }
     // Increment right by 1
     else {
       right++;
     }
   }
   // Return the value of cnt
   return cnt;
}
int main() {
   string alpha = "abcdda";
   int K = 4;
   cout << "The number of substrings containing all K characters at least once is " << numberOfSubstrings(alpha, K);
   return 0;
}

输出

The number of substrings containing all K characters at least once is 4

时间复杂度 - O(N),用于滑动窗口。

空间复杂度 - O(K),用于在映射中存储频率。

程序员也可以使用数组来存储字符的频率而不是映射,因为我们可以比映射更快地访问数组中的元素。为了进行更多练习,程序员尝试解决我们需要计算仅包含所有K个字符一次的字符串数量的问题。

更新于:2023年8月29日

93 次浏览

开启您的职业生涯

完成课程获得认证

开始学习
广告
© . All rights reserved.