字符串压缩与字符串解码(leetcode题)

1,字符串压缩

题目要求

字符串压缩。利用字符重复出现的次数,编写一种方法,实现基本的字符串压缩功能。比如,字符串aabcccccaaa会变为a2b1c5a3。若“压缩”后的字符串没有变短,则返回原先的字符串。你可以假设字符串中只包含大小写英文字母(a至z)。

示例1:
输入:“aabcccccaaa”
输出:“a2b1c5a3”

示例2:
输入:“abbccd”
输出:“abbccd”
解释:“abbccd"压缩后为"a1b2c2d1”,比原字符串长度更长。

提示:字符串长度在[0, 50000]范围内。

来源:力扣(LeetCode)
链接: https://leetcode-cn.com/problems/compress-string-lcci/.

题目分析

思路简单,从第二个字符开始,与第一个字符比较,若相等,则累加计数,若不等,将之前计数完成的字符+字符个数加到字符串末尾,并重新设置要比较的字符,且重新计数。见下面代码(C++)

代码

class Solution {
public:
    string compressString(string S) {
        int n=S.length();
        if(n==0) return S;
        string ans="";
        int cnt=1;
        char ch=S[0];
        for(int i=1;i<n;i++)
        {
            if(S[i]==ch)
            {
                cnt++;
            }
            else{
                ans+=ch+to_string(cnt);
                ch=S[i];
                cnt=1;
            }
        }
        ans+=ch+to_string(cnt);//加上最后一个元素
        int m=ans.length();
        return m<n?ans:S;
    }
};

``

2,字符串解码

题目要求

给定一个经过编码的字符串,返回它解码后的字符串。

编码规则为: k[encoded_string],表示其中方括号内部的 encoded_string 正好重复 k 次。注意 k 保证为正整数。

你可以认为输入字符串总是有效的;输入字符串中没有额外的空格,且输入的方括号总是符合格式要求的。

此外,你可以认为原始数据不包含数字,所有的数字只表示重复的次数 k ,例如不会出现像 3a 或 2[4] 的输入。

示例:
s = “3[a]2[bc]”, 返回 “aaabcbc”.
s = “3[a2[c]]”, 返回 “accaccacc”.
s = “2[abc]3[cd]ef”, 返回 “abcabccdcdcdef”.

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/decode-string/.

题目分析及代码

此题有两种解法,我看到题目最先想到的是用栈辅助,后来看题解发现还可以递归,或者说是dfs方法。下面分别介绍这两种方法及代码(C++)

(1) 用栈辅助

分析该题,发现要先处理最内的方括号(如果有方括号嵌套的话),这和栈先入后出的思想吻合。因为我用c++做题,很多童鞋用两个栈辅助,一个保存字符,一个保存数字,这是因为压入栈的时候,要把方括号 [ 前面的字符与数字同时压栈,留待稍后处理。我为了简便,参考了一个大佬的简明思想,用了pair,而pair与stack不太好一起用,所以用vector模拟栈。
思路如下:(做此题建议大家看 Krahets的精选题解,那个大佬分析的很好,代码也非常之简结,不过只有JAVA和Python)
挨个遍历字符串中每个字符,会遇到下面四种情况:
1,字符为数字
处理数字字符,将之转换为数字
2,字符为 ’ [ ’
首先将左括号前的字符res和数字num压入栈中,并将保存字符和数字的变量res和num 置为初始值,便于重新保存方括号里面的字符和数字
3,字符为 ’ ] ’
栈顶元素出栈,并拼接字符串,如3[a2[c]],遇到c右边的 ] 之后,当前栈顶元素为{a,2},分别保存在last_res和cur_num中,当前字符串变量res为c,num=0,则拼接好的字符串应该为res=last_res+cur_num*res
4,字符为字母
加到字符串res末尾

代码如下:

class Solution {
public:
    typedef pair<int,string> pa;
    string decodeString(string s) {
        vector<pa> vestack;
        int retis=0;
        string res="";
        for(auto i:s)
        {
            if(i=='[')
            {
                vestack.push_back({retis,res}); //[ 左边的字母和表示[]里面字母要重复的次数进栈
                retis=0;        //新的[]里的字符和数字置零,重新记录
                res="";
            }
            else if(i==']')
            {
                pa tmp=vestack[vestack.size()-1]; //栈顶元素弹出
                int cur_retis=tmp.first; //当前[]里面字符串要重复的次数
                string last_res=tmp.second;//[]之前的字符串
                vestack.pop_back();
                for(int i=0;i<cur_retis;i++) //[]前的字符串加上cur_retis个[]里面的字符串
                {
                    last_res +=res;
                }
                res=last_res;
            }
            else if('0'<=i&&i<='9')
            {
                retis=(retis*10)+(i-'0');//*10是为了遇到重复次数大于10的情况,该步骤将字符数字转换为数字
            }
            else
                res+=i; //遇到字母,添加到当前res最后
        } 
        return res;
    }
};

其中,auto不太明白的可以参考这个博主的博客
https://blog.csdn.net/qq_34037046/article/details/85221622.

(2) 递归(DFS)

递归呢,思路其实和栈差不多,关键是要想清楚递归开始与终止条件。这里提供一种思路,即遇到 [ 开启递归,并处理跳出下一层递归之后的字符串拼接工作,遇到 ] 结束递归,返回上一层。

代码如下:

class Solution {
public:
    string decodeString(string s) {
        int i=0;
        return digui(s,i);//dfs
    }
    string digui(const string& s,int& i) //如果这里i不是引用传递,在递归时i的值不变,          
    {                                   //导致跳出递归后难以定位i位置
        string res="";
        int renums=0;
        while(i<s.length())
        {
            if(s[i]>='0'&&s[i]<='9')
            {
                renums=(renums*10)+(s[i]-'0');
            }
            else if(s[i]=='[')//ch为[时开启递归
            {
                string tmp=digui(s,++i);
                while(renums)//跳出下一层递归后,令[]前的字符串+[]前数字renums个[]里的字符串
                {
                    res+=tmp;
                    renums--;
                }
            }
            else if(s[i]==']')//递归结束条件
            {
                return res;
            }
            else{
                res+=s[i];
            }
            i++;
        }
        return res;
    }
};

在写这个程序的时候,我因为digui 函数传入参数 i 的时候没有用引用传参,导致结束下一层循环之后,i 的值没有变化,无法定位 i 的具体数值,自己给 i 赋值,发现有一类样例过不了,感觉自己思路对,但是可能还是没想到位吧,所以直接引用传参还是方便清晰啊。此外,也可以不用 i ,有一个题解用了istringstream传参,直接传入每个字符,也很方便。

PS:补充一个类似这道题的字符解码题,是前几天腾讯一面时候要求写的,那个题目做了一点改动,给的字符串格式为 HG[3|B[2|CA]]F,加了 | 字符,展开为HGBCACABCACABCACAF。这个的代码待补充。。。

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值