C++编程练习

3 篇文章 0 订阅

字符的左右移动

题目

  • 字符串是任意的和字母的组合,设计算法,把都移到最左边,字母都移到最右边且保持相对顺序不变。

实现

  • 逆序处理字符串。双指针,一个指针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是要匹配的字符串。

实现

  • 递归,从后往前比较。
  • ij分别是sp当前考虑的字符的位置,初值分别为slen-1plen-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);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值