字符的左右移动
题目
- 字符串是任意的
*
和字母的组合,设计算法,把*
都移到最左边,字母都移到最右边且保持相对顺序不变。
实现
- 逆序处理字符串。双指针,一个指针
alpha
最初指向最右边的字符,另一个last
指针最初指向最右边的*
。 - 当
alpha
指向字母时,就和last
指向的字符互换,并且这两个指针同时向左移一位。 - 当
alpha
指向*
时,只有alpha
向左移动一位。 - 当
alpha<0
时,结束。
代码
void change(string& s)
{
int len = s.length();
int alpha = len - 1;
//找到最右边的字母
while (alpha>=0&&s[alpha] == '*')
alpha--;
int last = len - 1;
while (alpha >= 0)
{
if (s[alpha] != '*')
{
swap(s[alpha--], s[last--]);
}
else
alpha--;
}
}
字符串的匹配
题意
- 支持
.
和*
的正则表达式匹配。 .
匹配任一字符,*
匹配0个或多个前面的字符。- 字符串
p
是匹配模式,s
是要匹配的字符串。
实现
- 递归,从后往前比较。
i
,j
分别是s
和p
当前考虑的字符的位置,初值分别为slen-1
和plen-1
.- 按照p[j]是
.
,*
还是字符分情况考虑:- 当
p[j]=‘.’
时,若(s,i-1,p,j-1)
匹配返回了true
,则(s,i,p,j)
返回true
。 - 当
p[j]=‘*’
时,若(s,i-1,p,j-2)
匹配返回了true
,则(s,i,p,j)
返回true
;否则依次从后往前遍历剩下的s
字符,如果遍历到s
下标为k
的字符满足s[k]==p[j-1]
或者p[j]==‘.’
,则当(s,k-1,p,j-2)
返回true
时,(s,i,p,j)
也返回true
。 - 当p[j]是其他字符时,只有当
s[i]==p[j]
而且(s,i-1,p,j-1)
返回true
时,(s,i,p,j)
才返回true
。
- 当
代码
bool isMatch(string &s,string &p)
{
return help(s,s.length()-1,p,p.length()-1);
}
bool help(string &s,int i,string &p,int j)
{
//特殊情况处理:若p的长度为0,只有当s的长度也为0时才返回true
if(j==-1)
return i==-1;
if(p[j]=='.')
return i>=0&&help(s,i-1,p,j-1);
if(p[j]=='*')
{
if(help(s,i-1,p,j-2))
return true;
for(int k=i;k>=0;k--)
{
//‘*’依次匹配1个,2个,3个,...相同的前字符p[j-1],
//直到s[k]与p[j-1]不匹配为止。
if(s[k]==p[j-1]||p[j-1]=='.')
{
if(help(s,k-1,p,j-2))
return true;
}
else
return false;
}
}
else
{
if(i>=0&&help(s,i-1,p,j-1))
return true;
}
return false;
}
字符串空格压缩
题意
- 将字符串中连续出现的空格压缩成一个并将以空格分开的字符串逆序打印出来。
实现
- istringstream:用于处理行内对每个单词。
#
void reverse(string &s)
{
int len=s.length();
if(len<=1)
return;
for(int i=0;i<len/2;i++)
{
swap(s[i],s[len-i-1];
}
}
void comp(string &s)
{
istringstream is(s);
string word;
s.clear();
while(is>>word)
{
reverse(word);
s=s+word+' ';
}
s.pop_back();
}
重复字符的压缩
题意
- 对字符串中重复出现的字母进行压缩,按要求输出压缩后的字符串。
- 比如字符串
xxyyyyyz
,压缩后为2x5yz
,其中z
只出现一次故不压缩。
实现
- 遍历啊遍历
代码
//将int转换成字符串
string num2str(int n)
{
string ans;
if(n==0)
return "0";
while(n)
{
char tmp='0'+n%10;
n/=10;
ans=tmp+ans;
}
return ans;
}
string dup(string &s)
{
int count=1;
string ans;
for(int i=1;i<s.length();i++)
{
if(s[i]==s[i-1])
count++;
else
{
if(count==1)
ans+=s[i];
else
ans=ans+num2str(count)+s[i];
count=1;
}
}
if(count==1)
ans+=s[i];
else
ans=ans+num2str(count)+s[i];
return ans;
}
第一个只出现一次的字符
题意
- 在一个字符串中找出第一个只出现一次的字符。
- 比如输入
abaccdeff
,输出b
实现
- 笨办法:在字符和出现的下标建立映射。
- 没有这个字符则加进去,否者让这个字符对应的下标设为-1.
代码
//假定这个出现仅一次的字符一定存在
char OnlyFirst(string &s)
{
if(s.length()==1)
return s[0];
map<char,int>mp;
for(int i=0;i<s.length();i++)
{
if(mp.count(s[i]))
mp[s[i]]=-1;
else
mp[s[i]]=i;
}
int minIndex=s.length();
for(auto iter=map.begin();ier!=map.end();iter++)
{
if(iter->second!=-1)
{
if(iter->second<minIndex)
minIndex=iter->second;
}
}
return s[minindex];
}
谁有更好的方法??
删除特定的字符
题意
- 给定原始字符
s
和模式字符串p
,要求在原始字符中删除所有在模式字符串中出现过的字符。
实现
- 在原始字符串中,把出现在模式字符串中的字符用后面的字符覆蓋上来。在匹配完后,原始字符串最后一个字符后面赋值为
'\0'
即可。 string
是顺序存储结构,每删除一个字符,后面的字符都要一个个移动到前面来,这样时间复杂度很高。
代码
void deleteString(string &s,string &p)
{
int slen=s.length();
int plen=p.length();
if(slen==0||plen==0)
return;
int hash[256]={0};
for(int i=0;i<plen;i++)
hash[p[i]]=1;
int slow=0;
int fast=0;
while(fast!=slen)
{
if(hash[s[fast]]!=1)
{
s[slow++]=s[fast];
}
fast++;
}
s=s.substr(0,slow);
}