(0001)删除字符串中的公共字符
题目: 输入两个字符串, 从第一字符串(下文称为x)中删除第二个字符串(下文简称为y)中所有的字符. 例如, 输入
They are students.
和aeiou
, 则删除之后的第一个字符串变成Thy r stdnts.
解题思路
最简单的思路
两层循环遍历, 每遍历到字符串 y 中的一个字符, 就在字符串 x 中找到相同的字符, 找到之后删除它,并将字符串 x 后面的字符整体向前移动1位。所以这个过程的时间复杂度是O(n³).
优化 - 解决顺序存储结构中删除后整体移动的问题
删除一个字符的另一个思路是: 不是某个指定的字符就保留
, 按照这种思维方式, 可以将需要保留的字符覆盖在原来的字符串上, 此时需要两个标记变量(或者说指针), 一个用于控制字符串 x 的整体遍历过程,一个记录要覆盖的位置, 这样的话,我们就能避免每一次删除后的整体平移,时间复杂度优化为O(n²)
, 如下图所示.
优化 - 引入hash表, 避免双层遍历
O(n²)
的时间复杂度是由遍历两个字符串产生的,引入hash表能够避免循环嵌套的问题,我采用的方式是对字符串 y, 建立一个hash表, 在字符串 y 中出现的字符, 在hash表中的值为1, 反之为0.- 参考标点符号和字母的ASCII码值, hash范围选成256就足够了.
关于选用hash表的方式: 用一个O(256)的空间复杂度,将时间复杂度从O(n^2)将为O(n),如果n很大的话,这个替换是值得的。
show the code
#include "iostream"
using namespace std;
void DeleteChar(char arr1[], char arr2[]);
int main()
{
char str1[] = "They are students.";
char str2[] = "aeiou";
cout<<str1<<endl;
DeleteChar(str1, str2);
cout<<str1<<endl;
getchar();
return 0;
}
void DeleteChar(char *arr1, char *arr2)
{
if (arr1 == NULL && arr2 == NULL) return;
// 创建hash表
int hash_table[256] = { 0 };
char *p1 = arr1;
char *p2 = arr2;
int index =0;
// 遍历字符串y
while(*p2 != '\0')
{
hash_table[(int)*p2] = 1;
p2++;
}
// 遍历字符串x
while (*p1 != '\0')
{
// 该字符不需要删除
if( 0 == hash_table[(int)*p1] )
{
arr1[index]= *p1;
index++;
}
p1++;
}
arr1[index]='\0';
}