计算前缀具有素数个不同字符的字符串的偶数索引

data structurec++server side programmingprogramming更新于 2024/10/2 6:05:00

在此问题中,我们将在给定的字符串中找到总无效字符。如果到特定偶数索引为止的总不同字符数为素数,则可以说该字符无效。

我们可以使用 map 数据结构在遍历字符串时计算不同字符的总数。此外,我们可以使用字符串来跟踪不同的数字。此外,对于每个字符,我们可以检查其索引是否为偶数以及不同字符是否为素数。

问题陈述 - 我们给出了一个包含 N 个字符的字符串 alpha。我们需要在给定的字符串中找到总无效字符。如果不同字符的总数是 [0, index] 范围内的素数,则该字符无效,其中 0 <= index < N 且索引为偶数。

示例

输入 

alpha = "ppqprs"

输出

2

解释

  • 第 2 个索引为偶数,且总不同字符数为 2,即质数。因此,第 2 个索引无效。

  • 第 4 个索引也是偶数,且总不同字符数为 3,即质数。因此,第 4 个索引也是无效的。

输入 

alpha = "tttttt";

输出 

0

解释

不同字符的总数为 1,因为字符串的所有字符都相同。

输入 

alpha = "abcdefgh";

输出 

3

解释

  • 在第 2 个索引处,不同字符的总数为 3。

  • 在第 4 个索引处,不同字符的总数为 5。

  • 在第 6 个索引处,不同字符的总数为 7。

方法 1

在此方法中,我们将找到 0 到 10,00,000 范围内的所有素数。之后,我们将使用 map 数据结构来存储不同字符。如果在任何偶数索引处,不同字符的数量为质数,我们将该索引视为无效索引。

算法

  • 步骤 1 - 执行 computePrimeNums() 函数以查找 0 到 10,00,000 范围内的所有质数。

  • 步骤 1.2 - 在 computePrimeNums() 函数中,用 1 初始化"primeNum"数组元素,假设所有数字最初都是质数。

  • 步骤 1.3 - 如果数字不是质数,我们需要将元素从 1 更新为 0。因此,更新第 0 和第 1 个索引处的元素,因为它们不是质数。

  • 步骤 1.4 - 在所有偶数索引处,将 1 替换为 0,因为偶数不是质数。

  • 步骤 1.5 - 接下来,对于每个奇数,我们需要检查它是否是质数。因此,开始遍历奇数。

  • 步骤 1.6 - 使用另一个嵌套循环遍历奇数并替换 p*q 索引处的元素,因为它不是质数。

  • 步骤 2 - 用 0 初始化"diffChars"变量,以存储特定索引之前不同字符的总数。此外,初始化"cnt"以存储无效字符的数量。我们将使用"freq"映射来存储字符的频率。

  • 步骤 3 - 开始迭代字符串,并且映射中字符的频率为 0,将字符添加到映射中,并将"difChars"增加 1。

  • 步骤 4 - 如果 p 可以被 0 整除,并且"diffChars"是质数,则将"cnt"的值增加 1。

  • 步骤 5 - 返回"cnt"值。

示例

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

// 存储素数的数组
int primeNum[300];
// 计算素数的函数
void computePrimeNums() {

    // 用 1 初始化数组
    memset(primeNum, 1, sizeof primeNum);
    primeNum[0] = primeNum[1] = 0;
    
    // 所有偶数都是非素数
    for (int p = 4; p <= 300; p += 2)
    primeNum[p] = 0;
    
    // 对于奇数
    for (int p = 3; p * p <= 300; p += 2) {
      if (primeNum[p]) {
      
         // 处理非素数
         for (int q = 3; q * p <= 300; q += 2)
         primeNum[p * q] = 0;
      }
   }
}
int getInvalidChars(int len, string alpha) {
    computePrimeNums();
    int diffChars = 0;
    
    // 存储最终答案
    int cnt = 0;
    
    // 存储字符频率
    unordered_map<char, int> freq;
    
    // 遍历字符串
    for (int p = 0; p < len; p++) {
   
      // 如果我们第一次得到一个角色
      if (freq[alpha[p]] == 0) {
         freq[alpha[p]]++;
         diffChars++;
      }
      
      // 对于偶数索引和 diffChars 是素数
      if (((p % 2) == 0) and primeNum[diffChars]) {
         cnt++;
      }
   }
   return cnt;
}
int main(){
    int len = 6;
    string alpha = "ppqprs";
    cout << "无效字符数为 " << getInvalidChars(len, alpha) << endl;
    return 0;
}

输出

无效字符数为 2

时间复杂度 − O(N + 300),因为我们遍历字符串并计算 300 范围内的所有素数。

空间复杂度 − O(1),因为我们使用常量空间来存储素数。

方法 2

在这种方法中,我们将使用字符串来跟踪不同的字符。此外,我们会在需要时检查素数,而不是预先计算素数。

算法

  • 步骤 1 - 用 0 初始化"cnt",用空字符串初始化"diffChars"。

  • 步骤 2 - 遍历字符串时,使用 find() 方法检查字符串第 p 个索引中的字符是否存在于"diffCHars"字符串中。如果不存在,则将一个字符附加到"diffChars"字符串。

  • 步骤 3 - 如果索引为偶数,并且"diffChars"字符串的长度为素数,则将"cnt"值增加 1。

  • 步骤 3.1 - 在 checkForPrime() 函数中,如果数字小于或等于 1,则返回 false。

  • 步骤 3.2 - 否则,进行迭代,直到 index*index 小于数字值。

  • 步骤 3.3 - 在循环中,如果数字可以被索引值整除,则返回 false。

  • 步骤 3.4 - 最后,返回 true。

  • 步骤 4 -最后返回'cnt'值。

示例

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

bool checkForPrime(int num) {
   if (num <= 1) {
      return false;
   }
   for (int p = 2; p * p <= num; p++) {
      if (num % p == 0) {
         return false; // 不是质数
      }
   }
   
   // 数字是质数
   return true;
}
int getInvalidChars(int len, string alpha) {

    // 存储最终答案
    int cnt = 0;
    string diffChars = "";
    
    // 遍历字符串
    for (int p = 0; p < len; p++) {
    
        // 如果我们第一次得到一个字符
        if (diffChars.find(alpha[p]) == string::npos) {
        	diffChars += alpha[p];
        }
        
        // 对于偶数索引且 diffChars 为素数
        if (((p % 2) == 0) and checkForPrime(diffChars.length())) {
            cnt++;
        }
    }
    return cnt;
}
int main() {
    int len = 6;
    string alpha = "ppqprs";
    cout << "无效字符数为 " << getInvalidChars(len, alpha) << endl;
    return 0;
}

输出

无效字符数为 2

时间复杂度 - O(N*D),其中 N 是字符串长度,D 是给定字符串中的不同字符总数。

空间复杂度 - O(1),因为我们不使用任何额外空间。

我们学习了两种在给定字符串中查找无效字符的不同方法。当给定一个包含数百万个字符的大字符串时,第一种方法非常快。第二种方法更节省空间,因为它不使用任何动态空间。


相关文章