字符串问题常用解决方法
哈希法
基本思路
哈希法:哈希法在字符串类型题中,一般用于查重,查是否出现,建立数组元素与下标的关系,能够起到快速查找的作用,判断是否出现过。
题目“确认字符互异”
确认字符互异:
原题链接
解题思路
题干提醒了:
1、字符串中的字符都是ASCII字符(建立128大小映射)
2、这里不让使用额外的存储结构(自实现hash)
方法:ASCII字符共128个,建立128大小的bool数组记为bool hashchar[128]
初始化为false,char类型可转为无符号整型,则能以字符为下标记为a
,遍历iniString
,如果第一次出现,则改为true
,下次遇到同样的字符则返回。
解题代码
class Different {
public:
bool checkDifferent(string iniString) {
// write code here
bool hashchar[128];
memset(hashchar,0,sizeof(hashchar));
for(char a:iniString){
if(hashchar[a])//如果出现过返回
return false;
else hashchar[a]=true;//没出现过的字符登记
}
return true;
}
};
题目“确定两串乱序同构”
确定两串乱序同构
原题链接
解题思路
串A能否由串B字符重组得到?即串A的每一个字符都在串B中出现。且出现的次数一致。
方法:
1、统计串A的每一个字符,再统计串B是否出现的一样多。
2、可建立128大小(ASCII表大小)的整型数组int charhash[128]
初始化为0
,遍历记录串A中的字符出现的次数即对每一个字符c
,++charhash[c]
。
3、再遍历一次B串,对每一个字符c
,--charhash[c]
,如果charhash[c]
为0则返回错误,说明不同构。
解题代码
class Same {
public:
bool checkSam(string stringA, string stringB) {
// write code here
int charhash[128];
memset(charhash,0,sizeof(charhash));
for(auto &c:stringA){
charhash[c]++;
}
for(auto &c:stringB){
if(!charhash[c])//为0的情况
return false;
else --charhash[c];
}
return true;
}
};
双指针
思路:双指针法一般用于字符原地操作,如翻转,原地快排;滑动窗口;维护最值序列。
题目“原串翻转”
原串翻转
解题思路
1、在不使用额外数据结构和储存空间的情况下(可以使用单个过程变量)
(原地调整:高位低位互换,如果不要求原地的话可以用个栈就解决了)
2、翻转一个给定的字符串
方法:
1、取字符串高位记为high
初始化为iniString.size()-1
,低位记为low
初始化为0
,过程变量temp
初始化为iniString [low]
,
2、每次high low交换后,--high;++low;
temp赋新的low值
解题代码
class Reverse {
public:
string reverseString(string iniString) {
// write code here
if(iniString.empty())return iniString;
int low=0,high=iniString.size()-1;
char temp=iniString[0];
while(low<high){
iniString[low]=iniString[high];
iniString[high]=temp;
--high;
++low;
temp=iniString[low];
}
return iniString;
}
};
截断复制
基本思路
截断复制也谈不上是什么方法,不过是按照题意修改字符串,比如空格替换,字符压缩等等题目,把需要找到需要修改的位置执行题意要求的操作罢了,如果说有什么要记的,那应该是字符串常用函数吧。比如查找 字符位置find(),返回字串substr(),追加字符
。string常用函数
题目“空格替换”
解题思路
找到每一个空格的位置,获得空格前面的子串,追加到结果字符串,再追加%20
。
重置字符串iniString
为子串。
解题代码
class Replacement {
public:
string replaceSpace(string iniString, int length) {
// write code here
int pos=-1;
string ret;
while((pos=iniString.find(' '))!=std::string::npos){
ret+=iniString.substr(0,pos);
ret+="%20";
iniString=iniString.substr(pos+1);
}
ret+=iniString;
return ret;
}
};
题目“字符串压缩”
解题思路
添加个计数器,计算连续相同的字符长度,最后再比较
解题代码
class Zipper {
public:
string zipString(string iniString) {
string res;
int size=iniString.size();
for(int i=0;i<size;++i){
int count=1;
while(i+1<size&&iniString[i]==iniString[i+1]){
++i;
++count;
}
res+=iniString[i];
res+=to_string(count);
}
if(res.size()>size)return iniString;
else return res;
}
};
翻转子串
解题思路
1、理解题意:
这题不是普通的完全倒序,而是循环移位,如字符串 s1=“abcd”;s2可能为:循环移位多个结果:abcd->bcda->cdab->dabc;这里的4个字符串都是匹配的。
2、解决方案:如果把原来被移走的字符留下来那么有:
abcd->abcda->abcdab->abcdabc->abcdabcd。
我们可以看见原来最后的结果是s1的两倍。且包括了 1 中的所有方案。
解题代码
class ReverseEqual {
public:
bool checkReverseEqual(string s1, string s2) {
// write code here
string s3=s1+s1;
if(s3.find(s2)!=std::string::npos){
return true;
}
else return false;
}
};