这一题好像有那么点小复杂
输入一行数字,如果我们把这行数字中的‘5’都看成空格,那么就得到一行用空格分割的若干非负整数(可能有些整数以‘0’开头,这些头部的‘0’应该被忽略掉,除非这个整数就是由若干个‘0’组成的,这时这个整数就是0)。
你的任务是:对这些分割得到的整数,依从小到大的顺序排序输出。
Time limit | Memory limit | OS | Source |
---|---|---|---|
1000 ms | 32768 kB | Windows | POJ |
输入包含多组测试用例,每组输入数据只有一行数字(数字之间没有空格),这行数字的长度不大于1000。
输入数据保证:分割得到的非负整数不会大于100000000;输入数据不可能全由‘5’组成。
对于每个测试用例,输出分割得到的整数排序的结果,相邻的两个整数之间用一个空格分开,每组输出占一行。
input | output |
---|---|
0051231232050775 | 0 77 12312320 |
输入多组数据,一组数据包括一行数字,把其中的“5”当做空格,以这些空格为界,分割这串数字以得到一堆整数,将这些整数从小到大排序后逐个输出,每个输出之间加一个空格。
首先需要输入多组数据,就需要用一个while来循环程序,当结束输入时退出循环,然后由于一开始输入的数据是一长串数字,为了不溢出,应选用字符串来储存,然后以5为界分割字符串,再将每个分割出来的字符串转为整型,然后进行排序,排序后输出结果。
AC通过的C++语言程序代码如下:
#include
#include
using namespace std;
void bubble_sort(int arr[], int len)
{
int i, j, change = 1;
for (i = 0; i < len - 1 && change != 0; i++)
{
change = 0;
for (j = 0; j < len - 1 - i; j++)
if (arr[j] > arr[j + 1])
{
swap(arr[j], arr[j + 1]);
change = 1;
}
}
}
int main()
{
string num[500];
string snum;
while (cin >> snum)
{
int len = 0;
int start = 0;
int n = 0;
bool ndone = false;
for (int i = 0; i < snum.size(); i++)
{
if (snum[i] != '5')
{
len++;
if (ndone)
{
start = i;
ndone = false;
}
}
if (i != 0 && snum[i - 1] != '5' && snum[i] == '5')
{
num[n] = snum.substr(start, len);
n++;
ndone = true;
len = 0;
}
else if (i == snum.size() - 1 && snum[i] != '5')
{
num[n] = snum.substr(start, len);
n++;
}
}
int *numl = new int[n];
for (int i = 0; i < n; i++)
numl[i] = stoi(num[i]);
bubble_sort(numl, n);
for (int i = 0; i < n - 1; i++)
cout << numl[i] << " ";
cout << numl[n - 1] << endl;
delete numl;
}
}
一开始声明了一个用于存放string的输出和一个string,前者用于存放分割出来的字符串,后者用来存放用户输入的字符串。
string num[500];
string snum;
使用了while来保证可以输入多组数据且在结束输出时会退出循环。
while (cin >> snum)
在程序里,声明了四个变量,分别用于标示需要分割出来的字符串长度、开始分割位置的角标、分割出来的字符串要放到的位置,和是否已经给start(开始分割的位置)赋过值。
int len = 0;
int start = 0;
int n = 0;
bool ndone = false;
解释一下这些变量的默认值的用处,len一开始赋0以方便后面计算要分割的长度,而一开始分割的位置必然在第0个字符,所以start初始值赋0,然后第一个分割出来的字符串应该放在num数组的第0角标位置,所以n赋0。再由于start已经赋过初始值,所以ndone默认为false
然后进入到while循环,第一个部分是一个for循环,这个for循环用于检查所输入的字符串的每一个数字,遇到5时将该5到前一个5之间的数字都分割出来放进num数组,并将最后一组数字也分割出来放进num数组。
//分割
for (int i = 0; i < snum.size(); i++)
{
if (snum[i] != '5')
{
len++;
if (ndone)
{
start = i;
ndone = false;
}
}
if (i != 0 && snum[i - 1] != '5' && snum[i] == '5')
{
num[n] = snum.substr(start, len);
n++;
ndone = true;
len = 0;
}
else if (i == snum.size() - 1 && snum[i] != '5')
{
num[n] = snum.substr(start, len);
n++;
}
}
下面介绍各部分是怎样实现的
首先是第一个if:
if (snum[i] != '5')
{
len++;
if (ndone)
{
start = i;
ndone = false;
}
}
这个if是当当前检查的数不是5时执行的,它的作用是,如果当前数不是5,就将要分割的数长度加一(len++),然后如果start还处于未赋值的状态(这里状态用布尔变量表示),就将当前的i赋给start,并将start改为已赋值的状态。
然后是第二个if:
if (i != 0 && snum[i - 1] != '5' && snum[i] == '5')
{
num[n] = snum.substr(start, len);
n++;
ndone = true;
len = 0;
}
这个if的执行条件是当前检测的数遇到了5,而且i不等于0(即现在判断的不是第一个数),且上一个数不是5,这是为了避免当有连续多个5或者第一个数是5时仍然执行了赋值动作,这会导致程序num里赋进了空值,导致程序不能正常运行。
接下来赋值就是将字符串snum的从start开始为len长度的字符串赋值到num数组的第n项。这里涉及到了一个string类函数,那就是snum.substr(start, len),这个函数的含义即如上述。
进行完了赋值动作之后,n就要自增,以保证下一个分割出来的字符串储存在num数组的下一个位置。经过了这些,start的值就需要重新赋值,于是在这里将start重新改为未赋值的状态(ndone = true;),需要分割的长度也需要重新计算,于是将len赋值回0(len=0)。
而第二个if还有一个else if,也就是第二个if的条件达不到的时候执行的:
else if (i == snum.size() - 1 && snum[i] != '5')
{
num[n] = snum.substr(start, len);
n++;
}
这个else if的条件为当i等于输入的字符串的长度减1(snum.size() - 1),也就是当前检查的数是输入的数的最后一个,而且这个数不是5。大家可以想到,之前的分割动作的触发条件是遇到5,但有没有遇到的不是5也需要将前面的字符串分割出来的情况?那就是最后一串数字,因为最后一串数字不是以5结尾。
这里的分割操作和上面的if里面的分割操作方法基本相同,不同的是因为已经是最后一串数字,start和len就不用再重新赋值,也就可以不理,这里之所以n++,是为了方便下面使用n当做num长度的时候不会与数字是以5结尾的情况(该情况else if不会执行)有所不同。
分割完了字符串,就应该把分割出来的字符串都转为整型方便排序了
int *numl = new int[n];
for (int i = 0; i < n; i++)
numl[i] = stoi(num[i]);
这里根据分割出来字符串的个数,动态创建了另一个存放整型数据的数组,然后利用stoi()函数将num里面的元素转为int类型存于数组numl中。
之后排序用到了一个自定义函数,这个函数是一个冒泡排序函数,关于冒泡排序,详见:经典排序算法(1)——冒泡排序算法详解,这里就不多做解释。
void bubble_sort(int arr[], int len)
{
int i, j, change = 1;
for (i = 0; i < len - 1 && change != 0; i++)
{
change = 0;
for (j = 0; j < len - 1 - i; j++)
if (arr[j] > arr[j + 1])
{
swap(arr[j], arr[j + 1]);
change = 1;
}
}
}
然后就是输出结果了:
for (int i = 0; i < n - 1; i++)
cout << numl[i] << " ";
cout << numl[n - 1] << endl;
delete numl;
这里依次输出了numl(有序)里面的每个元素加一个空格,这里为了防止最后一个数输出后多了一个空格导致PE错误,最后一个元素就单独输出了。最后用delete释放numl的空间。