为了得到字符串 B,需要从字符串 A 中追加的最少子序列

data structurec++server side programmingprogramming

在这道题中,我们需要使用字符串 str1 的子序列来构造字符串 str2。为了解决这个问题,我们可以找到字符串 str1 的子序列,使其能够覆盖最大长度为 str2 的子字符串。在这里,我们将学习两种不同的解决方法。

问题描述 – 我们给出了两个长度不同的字符串 str1 和 str2。我们需要根据以下条件从 str1 构造 str2。

  • 从 str1 中选取任意子序列,并将其附加到新字符串(初始为空)。

我们需要返回构造 str2 所需的最少操作次数,如果无法构造 str2,则打印 -1。

示例

输入 – str1 = "acd", str2 = "adc"

输出 – 2

解释

  • str1 的第一个子序列是 'ad'。因此,我们的字符串可以是"ad"。

  • 之后,我们可以从 str1 中取出"c"子序列,并将其附加到"ad"后,使其成为"adc"。

输入– str1 = "adcb", str2 = "abdca"

输出– 3

解释

  • 第一个子序列是 str1 中的"ab"。

  • 之后,我们可以取出"dc"字符串,结果字符串将是"abdc"。

  • 接下来,我们可以取出"a"子序列,使其成为最终字符串"abdca"。

方法 1

在此方法中,我们将迭代 str1 以查找多个子序列,并将其附加到结果字符串中。

算法

  • 定义长度为 26 的 'arr' 数组,并将所有元素初始化为 0,以存储字符在 str1 中的存在情况。

  • 迭代 str1,并根据字符的 ASCII 值更新数组元素的值。

  • 定义 'last' 变量并将其初始化为 -1,以跟踪最后访问的元素。另外,定义"cnt"变量并将其初始化为0,以存储操作次数。

  • 使用循环开始遍历str2。

  • 如果当前字符不在str1中,则返回-1。

  • 使用"last + 1"值初始化"j"变量。

  • 使用while循环进行迭代,直到"j"的值小于len,且str1[j]不等于该字符。

  • 如果"j"的值大于"len",则遍历"str1"。增加"cnt"变量的值,将"last"初始化为 -1,因为我们需要再次遍历"str1",将"i"的值减 1,因为我们需要再次考虑当前字符,使用"continue"关键字继续迭代。

  • 将"last"变量的值更新为"j"。

  • 循环所有迭代完成后,返回"cnt + 1"。此处,由于我们不考虑最后一次操作,因此需要将"cnt"加 1。

示例

#include <iostream>
using namespace std;

// 函数用于计算从字符串 str1 的子序列中获取字符串 str2 所需的最少操作次数。
int minOperations(string str1, string str2){
    int len = str1.length();
    // 创建一个大小为 26 的数组,用于存储字符串 str1 中字符的存在情况。
    int arr[26] = {0};
    // 存储字符串 str1 中字符的存在情况。
    for (int i = 0; i < len; i++){
        arr[str1[i] - 'a']++;
    }
    // 存储字符串 str1 的最后一个迭代索引。
    int last = -1;
    // 存储操作次数。
    int cnt = 0;
    for (int i = 0; i < str2.length(); i++){
      char ch = str2[i];
      // 如果该字符不存在于字符串 str1 中,则返回 -1。
      if (arr[ch - 'a'] == 0){
         return -1;
      }
      // 从字符串 str1 的第 j 个索引开始迭代以找到字符 ch。
      int j = last + 1;
      while (j < len && str1[j] != ch){
          j++;
      }
      // 如果 j 等于字符串 str1 的长度,则增加计数,将 last 设置为 -1,并减少 i。
      if (j >= len){
         cnt++;
         last = -1;
         --i;
         continue;
      }
      // 将最后设置为 j。
      last = j;
   }
   // 返回 cnt + 1,因为我们还没有计算最后一个操作。
   return cnt + 1;
}
int main(){
   string str1 = "acd", str2 = "adc";
   int operations = minOperations(str1, str2);
   cout << "从字符串 A 的子序列创建字符串 B 所需的最少操作数为: " << operations << "\n";
   return 0;
}

输出

从字符串 A 的子序列创建字符串 B 所需的最少操作数为: 2

时间复杂度 – O(N*M),其中 N 是 str2 的长度,M 是 str1 的长度。

空间复杂度 – O(1),因为我们不使用任何动态空间。

方法 2

在此方法中,我们将使用 map 和 set 数据结构来提高上述方法的效率。解决问题的逻辑与上述方法相同。

算法

  • 定义 'chars_mp' 以将 char -> set{} 存储为键值对。

  • 在 map 中,存储 str1 字符串中特定字符所在的索引集合。

  • 定义 'last' 和 'cnt' 变量

  • 开始遍历 str2。如果包含当前字符索引的集合大小为零,则返回 -1。

  • 在当前字符索引集合中查找"last"的上限。

  • 如果未找到上限,则将"cnt"的值增加 1,将"last"设置为 -1,将"I"的值减少 1,然后使用 continue 关键字。

  • 更新"last"变量的值。

  • 循环迭代完成后,返回"cnt"变量的值

示例

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

// 函数用于计算从字符串 str1 的子序列中获取字符串 str2 所需的最少操作次数。
int minOperations(string str1, string str2){
    // 字符串 str1 的长度
    int len = str1.length();
    // 创建映射来存储 str1 中每个字符的索引集合
    map<char, set<int>> chars_mp;
    // 遍历 str1 中的字符,并将每个字符的索引存储在 map 中
    for (int i = 0; i < len; i++){
 	  chars_mp[str1[i]].insert(i);
    }
    // 存储 str1 中最后访问的索引
    int last = -1;
    // 存储所需的计数
    int cnt = 1;
    // 遍历 str2 中的字符
    for (int i = 0; i < str2.length(); i++){
        char ch = str2[i];
        // 如果 str2[i] 的索引集合为空,则返回 -1
        if (chars_mp[ch].size() == 0){
        return -1;
        }
        // 如果 str2[i] 的索引集合不为空,则在 str2[i] 的索引集合中找到 last 的上界
        // 找到 str2[i] 中大于 last 的最小索引
        auto it = chars_mp[ch].upper_bound(last);
        // 如果上界等于集合的末尾,则增加计数并将 last 更新为 -1
       	if (it == chars_mp[ch].end()){
          last = -1;
          cnt++;
          // 将 I 减 1 以再次处理当前字符
          --i;
          continue;
      	}
      //更新最后到当前索引
      last = *it;
   }
   return cnt;
}
int main(){
   string str1 = "adcb", str2 = "abdca";
   int operations = minOperations(str1, str2);
   cout << "从字符串 A 的子序列创建字符串 B 所需的最少操作数为: " << operations << "\n";
   return 0;
}

输出

从字符串 A 的子序列创建字符串 B 所需的最少操作数为: 3

时间复杂度 – O(N*logN),因为我们遍历 str2 并在循环中找到"最后一个"索引的上界。

空间复杂度 – O(N),因为我们使用 map 来存储字符索引。


相关文章