用 O(1) 额外空间从字符串中删除重复字符


在这个问题中,我们的任务是删除字符串中除了每个字符第一次出现之外的所有重复字符。此外,还需要在不使用任何额外空间的情况下解决问题,并且空间复杂度必须为 O(1)。本文使用了各种方法。一种方法是定义布尔数组来确定字符的重复情况,其中布尔数组的索引映射到每个字母。在第二种方法中,使用位操作的概念从结果字符串中删除重复字符。

让我们探索这篇文章,了解如何使用 Java 编程语言来解决它。

为您展示一些实例

实例 1

如果字符串 = “tutorialspoint”

应用算法后 -

结果字符串 = “tuorialspn”

实例 2

如果字符串 = “learningmaterial”

应用算法后 -

结果字符串 = “learnigmt”

多种方法

我们提供了不同方法的解决方案。

  • 使用大小为 26 的布尔数组

  • 使用单个整数位。

方法 1:使用大小为 26 的布尔数组

为了解决这个问题,我们将使用一个包含 26 个元素的布尔数组。每个字母都与布尔数组的索引映射,以指示字符的重复情况。

英语字母到布尔数组的映射

'a' ⇒ found[0]
'b' ⇒ found[1]
'c' ⇒ found[2]
'd' ⇒ found[3]
.
.
.
'z' ⇒ found[25

这里,如果 found[i] = True,则表示映射到索引 i 的字符已存在于字符串当前字符的左侧。因此,我们不再需要使用该字符。

如果 found[i] = False,则表示映射到索引 i 的字符尚未出现,因此需要考虑它并将其插入到结果字符串中。

算法:removeDuplicatesFromStr(str)

步骤 1:创建一个名为 found 的数组。

步骤 2:声明一个等于 -1 的写指针。

步骤 3:初始化 for 循环以遍历字符串“str”。

步骤 4:设置整数 d = ASCII(str[read]) – 97。

步骤 5:如果 found[d] = False,则设置 found[d] = True。

步骤 6:将写指针的值增加 1。

步骤 7:更新输入字符串,然后将计算出的字符串的最后一个字符分配为 NULL。

步骤 8:最后,在消除冗余字符后打印结果。

示例

#include <iostream>
using namespace std;
void removeDuplicatesFromStr(char inputString[]) {
   // found is a Boolean array whose index mapped to the alphabets
   bool present[26] = {false};
   // write pointer, tells the place of writing
   int write = -1;
   //use for loop 
   for (int read = 0; inputString[read] != '\0'; ++read) {
       // search bit to check character's repetition
       int d = (int)inputString[read] - 97;
       // if the character did not come yet
       if (present[d] == false) {
           present[d] = true;
           write += 1;
           inputString[write] = inputString[read];
       }
   }
   // set last character of resultant string to NULL
   inputString[write+1] = '\0';
}

int main() {
   char inputString[10000];
   int N;
   cout << "Input String for removing duplicates: ";
   cin >> inputString;
   removeDuplicatesFromStr(inputString);
   cout << "Output String after removing duplicates: " << inputString << endl;

   return 0;
}

输出

Input String for removing duplicates: learningmaterial
Output String after removing duplicates: learnigmt

程序的时间复杂度 = O(N)

程序的空间复杂度 = O(26) = O(1)

方法 2:使用单个整数位

为了解决这个问题,我们创建一个整数,其位告诉我们字符是否重复。

C++ 中整数的大小 = 4 字节 = 4*8 位 = 32 位。

英语字母表中的字符数 = 26

英语字母表数 < 整数中的位数,

因此,我们可以使用整数的不同位来表示英语字母表中的每个字符。

英语字母表到整数的映射

'a' ⇒ bit 0 ⇒ (int)'a' - 97
'b' ⇒ bit 1 ⇒ (int)'b' - 97
'c' ⇒ bit 2 ⇒ (int)'c' - 97
'd' ⇒ bit 3 ⇒ (int)'d' - 97
.
.
.
'z' ⇒ bit 25 ⇒ (int)'z' - 97

如果 'a' 出现在字符串中,则位 0 被设置为 1。

对每个字符执行类似的操作。

这里,如果整数的位 d = 1,则表示映射到位 d 的字符已存在于字符串当前字符的左侧。因此,我们不再需要使用该字符。

如果整数的位 d = 0,则表示映射到位 d 的字符尚未出现,因此需要考虑它并将其插入到结果字符串中。

算法:removeDuplicates(str)

步骤 1:创建一个名为 found 的整数变量。

步骤 2:声明一个等于 -1 的写指针。

步骤 3:初始化 for 循环以查找用于检查重复的位。

步骤 4:设置整数 d = ASCII(str[read]) – 97。

步骤 5:如果 'd' 不存在于 'found' 中,则将 'd' 插入到 found 中。

步骤 6:将写指针的值增加 1。

步骤 7:更新输入字符串,然后将计算出的字符串的最后一个字符分配为 NULL。

步骤 8:最后,在消除冗余字符后打印结果。

示例

#include <iostream>
using namespace std;
void removeDuplicates(char inputStr[]) {
   // found is an integer whose bits mapped to the alphabets
   int found = 0;
   // write pointer, tells the place of writing
   int write = -1;

   for (int read = 0; inputStr[read] != '\0'; ++read) {
       // find bit for checking repetition
       int d = (int)inputStr[read] - 97;

       // if character not came yet
       if ((found & (1<<d)) == 0) {
           found = found | (1<<d);
           write += 1;
           inputStr[write] = inputStr[read];
       }
   }

   // set last character of resultant string to NULL
   inputStr[write+1] = '\0';
}

int main() {
   char inputStr[10000];
   int n;

   cout << "Input String for removing duplicates: ";
   cin >> inputStr;

   removeDuplicates(inputStr);

   cout << "Output String after removing duplicates: " << inputStr << endl;

   return 0;
}

输出

Input String for removing duplicates: tutorialspoint
Output String after removing duplicates: tuorialspn

程序的时间复杂度 = O(N)

程序的空间复杂度 = O(1)

在本文中,我们提供了两种方法来解决问题,使用 O(N) 的时间复杂度和 O(1) 的空间复杂度。

更新于: 2023 年 8 月 23 日

268 次浏览

开启您的 职业生涯

通过完成课程获得认证

开始
广告