程序员面试金典 1.6

String Compression:通过将字符串中连续的字符使用数字替代可以对字符串进行压缩,例如aabcccccaaa可以压缩为a2b1c5a3。如果压缩后的字符串比原始字符串长,则不进行压缩。假设字符串中只包含字母。

直观解法很简单,遍历字符串,将每个字符拷贝到一个新的缓冲区中,并进行计数。

class Solution {
public:
    string compressString(string S) {
        string strCpr;
        int iCnt = 0;
        for(size_t i = 0; i < S.size(); i++)
        {
            iCnt++;
            if(i == S.size() - 1 || S[i] != S[i + 1]){
                strCpr += S[i] + to_string(iCnt);
                iCnt = 0;
            }
        }
        if(strCpr.size() < S.size()) return strCpr;
        else return S;
    }
};

方法是可行的,但是复杂度为O(n + k ^ 2)n是输入字符串的长度,k为压缩后的字符串中的字母个数,例如aabccdeeaa就是6(可能是因为Java的字符串连接操作)。

可以用ostringstream来改进这一点,时间从16ms提升到了8ms。如果是C语言的话可以用sprintf()

class Solution {
public:
    string compressString(string S) {
        ostringstream oss;
        int iCnt = 0;
        for(size_t i = 0; i < S.size(); i++)
        {
            iCnt++;
            if(i == S.size() - 1 || S[i] != S[i + 1]){
                oss << S[i] << iCnt;
                iCnt = 0;
            }
        }
        if(oss.str().size() < S.size()) return oss.str();
        else return S;
    }
};

上面两种方法都是将字符串压缩后再和原始字符串比较的。

我们可以提前计算出压缩后字符串的长度,如果有必要压缩,再进行压缩,这样可以减少不必要的空间,毕竟输入数据长度可能有50000。这种方法的缺点是需要一次额外的遍历,而且会导致代码重复。

class Solution {
public:
    string compressString(string S) {
        size_t cprLen = cntCompression(S);
        if(cprLen >= S.size()) return S;
        ostringstream oss;
        int iCnt = 0;
        for(size_t i = 0; i < S.size(); i++)
        {
            iCnt++;
            if(i == S.size() - 1 || S[i] != S[i + 1]){
                oss << S[i] << iCnt;
                iCnt = 0;
            }
        }
        return oss.str();
    }
private:
    size_t cntCompression(const string &S)
    {
        size_t ret = 0;
        int iCnt = 0;
        for(size_t i = 0; i < S.size(); i++)
        {
            iCnt++;
            if(i == S.size() - 1 || S[i] != S[i + 1]){
                ret++;
                ret += to_string(iCnt).size();
                iCnt = 0;
            }
        }
        return ret;
    }
};

注:由于多了一次遍历,时间反而变长了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值