至少包含前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.