字符串压缩与解压 题解

题目描述
文本压缩有很多种方法,这里我们只考虑最简单的一种:把由相同字符组成的一个连续的片段用这个字符和片段中含有这个字符的个数来表示。例如 ccccc 就用 5c 来表示。如果字符没有重复,就原样输出。例如 aba 压缩后仍然是 aba。

解压方法就是反过来,把形如 5c 这样的表示恢复为 ccccc。

本题需要你根据压缩或解压的要求,对给定字符串进行处理。这里我们简单地假设原始字符串是完全由英文字母和空格组成的非空字符串。

输入格式
输入第一行给出一个字符,如果是 C 就表示下面的字符串需要被压缩;如果是 D 就表示下面的字符串需要被解压。第二行给出需要被压缩或解压的不超过1000个字符的字符串,以回车结尾。题目保证字符重复个数在整型范围内,且输出文件不超过1MB。

输出格式
根据要求压缩或解压字符串,并在一行中输出结果。

输入样例 1
C
TTTTThhiiiis isssss a tesssst CAaaa as
Copy
输出样例 1
5T2h4is i5s a3 te4st CA3a as
Copy
输入样例 2
D
5T2h4is i5s a3 te4st CA3a as10Z
Copy
输出样例 2
TTTTThhiiiis isssss a tesssst CAaaa asZZZZZZZZZZ

分析:
输入C压缩:
只要对每一个元素都不断检验其后面的元素判断是否相同以判断一下该元素有多少连续重复,每个元素刚开始都只有1个,如果后面有一个连续相同计数就+1,最后输出计数和这个元素一个连续相同都没有就直接输出这个元素。

注意:已经记录过的连续元素不需要再次从它开始向后检测,比如TTTTA
从0位置T开始不断向后检测,直到发现4位置的T和后面的A不相同,此时对0位置T的计数结束,计数为5,这5个T是一个整体了都已经处理完接下来应判断之后的5位置的A后面没有一个连续相同,直接输出A,所以最后输出为5TA

但是如果不把连续地元素当一个整体从5位置开始继续判断,而是直接继续判断位置1的T就会出现问题,对0位置T计数为5,对1位置T也进行了计数,计数为4,同理2位置计数为3,3位置为2,4位置为1后面没有连续相同直接输出,A没有连续相同直接本身,所以最后输出为5T4T3T2TTA,显然错误

输入D解压:
对于每个字母只需要找到字母前的数字a,然后循环输出a个字母即可

注意:数字不一定是一位数,即不能只靠c>=‘0’&&c<='9’得到数字,数字有可能为2位数,3位数…同上面一样,对于数字需要找到连续地数字字符再累加才能得到正确的数字。这样是以数字为考虑对象,很麻烦,如果以字母为对象比较简单。
字符串中的字母只有两种情况,第一种前面的字符为字母型,即该字母只有1个不需要前面加数字输出,第二种前面字符为数字型,此时得到数字,输出相应个该字母。可以把字符串分为几段,字母 数字 字母 数字 …这样不断判断元素是数字还是字母就可以完成分段,数字段是连续地数字型字符,累加即可得到正确的数字。

代码:

#include<iostream>
using namespace std;
int main()
{
	char ch;
	cin>>ch;
	getchar(); 
	string aim;
	getline(cin,aim);
    if(ch=='C')//压缩 
    {
    	int start=0,s=1; 
    	for(int i=start;i<aim.length();i++)
    	{
    		if(aim[i+1]==aim[i])
    		{
    			s=s+1;
			} 
			if(aim[i+1]!=aim[i])
			{
				if(s!=1)
				cout<<s<<aim[i];
				else cout<<aim[i];
				s=1;
				start=i+1;
			}
		} 
	}
	else if(ch=='D')//解压
	{
		int start=0,end=aim.length();
		for(int i=0;i<aim.length();i++)
		{
			if(aim[i]<'0'||aim[i]>'9')
			{
				end=i;
				int num=0,a=1;
				for(int j=end-1;j>=start;j--)
				{
					num=num+a*(aim[j]-'0');
					a=a*10;
				}
				if(num!=0)
				{
					for(int j=0;j<num;j++)cout<<aim[i];
				}
				else cout<<aim[i];
				start=end+1; 
			}
			else continue;
		}
	} 
	return 0;
} 

主要使用了start和end来标记下一次需要操作的字符串范围,每次操作完相应对start,end重新赋值就能灵活改变下一次操作的范围。【和插旗子类似】

猜你喜欢

转载自blog.csdn.net/qq_40315080/article/details/85251256