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;
}
};
注:由于多了一次遍历,时间反而变长了。