C++ 通过替换给定字符串中的’?’得到的按字典顺序最小的具有周期K的字符串

C++ 通过替换给定字符串中的’?’得到的按字典顺序最小的具有周期K的字符串

一个字符串是周期为K的,当且仅当它每K个字符重复一次。例如,字符串 “abcabcabc” 是一个周期为3的字符串,因为它每3个字符重复一次。字符串 “abcabc?abc” 不是一个周期为3的字符串,因为字符 ‘?’ 没有每3个字符重复一次。

问题陈述

给定一个包含N个小写字符的字符串”str”和一个正整数K,目标是用小写字母替换字符串”str”中的每个字符’?’,使得结果字符串形成长度为K的周期。如果无法找到满足给定条件的字符串,则输出“-1”。

字符串”str”可以包含任意数量的小写字符,包括’a’,’b’,’c’,……,’z’。

字符串”str”也可以包含字符’?’。

正整数K必须大于或等于1。

如果无法找到满足给定条件的字符串,则程序应打印“-1”。

示例

输入

“aabb????”, K = 4

输出

aabbaabb

输入

“xxyy????”, K = 2

输出

-1

解决方案

一个直观的寻找修改后字符串的方法可以通过以下步骤实现。

生成给定字符串中“?”字符的所有可能替换组合。

  • 对于每个组合,相应地替换“?”字符。

  • 检查生成的字符串是否具有长度为K的周期。如果是,则将其存储为候选解。

  • 在检查完所有组合之后,比较候选解并选择字典排序最小的一个。

  • 返回具有长度为K的字典排序最小字符串,如果没有找到有效解,则返回“-1”。

朴素的方法涉及生成所有可能的组合,这可能计算成本很高。随着字符串的长度和“?”字符的数量增加,组合的数量将呈指数级增长。因此,这种方法对于大型输入字符串不高效。

更优化的方法是使用一个高效的算法,避免了穷举生成组合,并根据特定条件直接修改字符串,以获得具有长度为K的字典排序最小字符串。

算法

  • 接受一个字符串str和一个整数K作为参数。

  • 验证字符串“str”的长度是否是K的倍数。如果不是,则返回“-1”,因为无法形成长度为K的周期。

  • 使用变量“i”遍历范围从0到K。

  • 创建一个空的map,称为“char_freq”,用于存储字符的频率计数。

  • 从索引“i”开始以每次K的增量遍历字符串“str”。

  • 更新“char_freq”中遇到的每个字符的频率计数。

  • 如果char_freq的大小大于2,则返回“-1”。

  • 如果char_freq的大小为1,检查“?”的频率是否不为零。如果是,则将str中位置为i,i+K,i+2K等的所有“?”字符替换为“a”。

  • 否则,如果char_freq的大小为2,则找到与“?”不同的字符,并将其存储在ch中。

  • 将str中位置为i,i+K,i+2K等的所有“?”字符替换为ch。

  • 返回修改后的字符串str。

示例:C++程序

代码片段 “stringNew()” 的设计是接受一个字符串 “str” 和一个整数 “K” 作为输入。最初,该函数验证 “str” 的长度是否被 “K” 整除。如果不是,则函数返回 -1。然而,如果长度条件满足,函数会在范围 [0, K] 上迭代。对于该范围内的每个索引 “i”,函数会创建一个名为 “char_freq” 的映射,以跟踪子字符串 “str[i: i + K]” 中每个字符的频率。然后,函数会检查 “char_freq” 的大小是否超过 2。如果条件为真,则函数返回 -1。另一方面,如果条件不满足,函数会将子字符串中的所有问号替换为 “char_freq” 中保存的最常见字符。最后,函数返回修改后的 “str”。

示例

#include <iostream>
#include <string>
#include <map>
using namespace std;

string stringNew(string &str, int K){
   // Verify whether the length of the string "str" is divisible by K.
   if (str.length() % K != 0){
      return "-1";
   }
   // Perform an iteration over the interval [0, K].
   for (int i = 0; i < K; i++){
      // Create a map to hold the frequency of characters in the substring str[i: i + K].
      map<char, int> char_freq;
      // Iterate over the string with increment of K in every iteration.
      for (int j = i; j < str.length(); j += K){
         char_freq[str[j]]++;
      }
      // If there are more than two different characters in the substring.
      if (char_freq.size() > 2){
         return "-1";
      }
      // If there is only one character in the substring.
      else if (char_freq.size() == 1){
         // If the character is '?', replace all occurrences of '?' in the substring with 'a'.
         if (char_freq['?'] != 0){
            for (int j = i; j < str.length(); j += K){
               str[j] = 'a';
            }
         }
      }
      // If there are two different characters in the substring.
      else{
         // Find a character other than '?'.
         char ch;
         for (auto &x : char_freq){
            if (x.first != '?'){
               ch = x.first;
            }
         }
         // Exchange all occurrences of '?' in the substring with ch.
         for (int j = i; j < str.length(); j += K){
            str[j] = ch;
         }
      }
   }
   // Return the modified string.
   return str;
}
int main(){
   string str = "aabb????";
   int K = 4;
   cout << "original string: "<< str << " and "<< "K = 4" <<endl;
   cout <<"new string: "<< stringNew(str, K) << endl;
   return 0;
}

输出

original string: aabb???? and K = 4
new string: aabbaabb

时间和空间复杂度分析

时间复杂度:O(N)

  • 代码由嵌套循环组成。外部循环在范围[0, K]内迭代,内部循环在字符串上以增量K进行迭代。

  • 外部循环的复杂度为O(K),因为它迭代K次。

  • 内部循环在字符串的一部分进行迭代,具体来说是字符串的位置i、i+K、i+2K等处的字符。内部循环迭代的次数由字符串的长度N和K的值决定。

  • 总体上,代码的时间复杂度为O(K * N/K) = O(N)。

  • 代码分配额外的空间来存储每个位置”i”处子字符串中字符的频率。此存储使用名为”char_freq”的映射来完成。

  • 映射”char_freq”用于记录子字符串中遇到的字符的频率。由于子字符串最多可以包含两个字符(包括’?’和另一个字符),因此该映射仅存储这些不同字符的频率。

  • 映射”char_freq”所需的空间与子字符串中存在的不同字符数成正比,这种情况下最多为2。

  • 因此,代码的空间复杂度可以视为O(1),因为空间使用保持恒定,不受输入大小的影响。

结论

本文提供了一个问题的简单和高效方法。文章提供了解决方案的方法、使用的算法和C++程序解决方案,以及对其时间复杂度和空间复杂度的深入分析。

Camera课程

Python教程

Java教程

Web教程

数据库教程

图形图像教程

办公软件教程

Linux教程

计算机教程

大数据教程

开发工具教程