分解字符串,转化及排序问题小结

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 20954 Accepted Submission(s): 5495


Problem Description
输入一行数字,如果我们把这行数字中的‘5’都看成空格,那么就得到一行用空格分割的若干非负整数(可能有些整数以‘0’开头,这些头部的‘0’应该被忽略掉,除非这个整数就是由若干个‘0’组成的,这时这个整数就是0)。

你的任务是:对这些分割得到的整数,依从小到大的顺序排序输出。

Input
输入包含多组测试用例,每组输入数据只有一行数字(数字之间没有空格),这行数字的长度不大于1000。

输入数据保证:分割得到的非负整数不会大于100000000;输入数据不可能全由‘5’组成。

Output
对于每个测试用例,输出分割得到的整数排序的结果,相邻的两个整数之间用一个空格分开,每组输出占一行。

Sample Input
0051231232050775

Sample Output
0 77 12312320

Source

Recommend
Eddy


MY CODE
#include<iostream>
#include<algorithm>

using namespace std;

int data[100005];
char str[100005];

int main()
{
    int i;
    int count;
    int num;
    int flag;
    while(~scanf("%s",str))
    {
        flag=0;
        count=0;
        num=0;
        memset(data,0,sizeof(data));
        for(i=0;i<strlen(str);i++)
        {
            if((str[i]-'0')==5&&(str[i-1]-'0')!=5)
            {
                num=0;
                count++;
            }
            if((str[i]-'0')!=5)
            {
                data[count]+=((str[i]-'0')%10);
                if((str[i+1]-'0')!=5&&(i+1<strlen(str)))
                    data[count]*=10;
                num++;
            }
        }
        if((str[0]-'0')==5)
            flag=1;
        if((str[strlen(str)-1]-'0')==5)
        {
            sort(data,data+(count));
            printf("%d",data[flag]);
            for(i=++flag;i<count;i++)
            {
                printf(" %d",data[i]);
            }
        }
        else
        {
            sort(data,data+(count+1));
            printf("%d",data[flag]);
            for(i=++flag;i<=count;i++)
            {
                printf(" %d",data[i]);
            }
        }
        printf("\n");
    }
    return 0;
}


注意几种特殊的数据,搞了半天,有失有得。
  • 512351234 以5打头
  • 2345555523 多个5连续在一起
  • 124523335 以5结尾


总结:学到了下面这个结构(以某个特殊字符串为分割符分隔一个串)

p = strtok(a,"5");
while(NULL != p)
{
p = strtok(NULL,"5");
}
wa了两次后开始看论坛上朋友们的代码,最后找到竟然是错在了qsort上,定义cmp时中间的减号写成了大于号,和定义sort的比较函数不一样啊,这个以前本来是记得的,长时间不用还真的不行。。

另外还发现了一个朋友写的不错,用到了sscanf函数,使得程序很简单,自己也顺便了解了下sscanf,具体用法贴在“杂乱知识”里,他的代码也贴在下面,有兴趣的可以学习。


#include <stdio.h> 
#include <stdlib.h> 
#include <string.h>
int cmp(const void* a,const void* b){ return *(int*)a-*(int*)b;}
int main()
{
    char a[1000];
    int b[1000],size,i;
    char* p;
    while(EOF!=scanf("%s",a))
    {
        size=0;
        p = strtok(a,"5");
        while(NULL != p)
        {
            b[size++] = atoi(p);
            p = strtok(NULL,"5");
        }
        qsort(b,size,sizeof(int),cmp);
        for(i=0;i<size-1;i++)
            printf("%d ",b[i]);
        printf("%d\n",b[i]);
    }
    return 0;
}


补充:

sscanf()函数

http://baike.baidu.com/view/1364018.htm

几个例子:

1. 常见用法。

  char buf[512] ;

  sscanf("123456 ", "%s", buf);//此处buf是数组名,它的意思是将123456以%s的形式存入buf中!

  printf("%s\n", buf);

  结果为:123456

  2. 取指定长度的字符串。如在下例中,取最大长度为4字节的字符串。

  sscanf("123456 ", "%4s", buf);

  printf("%s\n", buf);

  结果为:1234

  3. 取到指定字符为止的字符串。如在下例中,取遇到空格为止字符串。

  sscanf("123456 abcdedf", "%[^ ]", buf);

  printf("%s\n", buf);

  结果为:123456

  4. 取仅包含指定字符集的字符串。如在下例中,取仅包含1到9和小写字母的字符串。

  sscanf("123456abcdedfBCDEF", "%[1-9a-z]", buf);

  printf("%s\n", buf);

  结果为:123456abcdedf

  当输入:

  sscanf("123456abcdedfBCDEF","%[1-9A-Z]",buf);

  printf("%s\n",buf);

  结果为:123456

  5. 取到指定字符集为止的字符串。如在下例中,取遇到大写字母为止的字符串。

  sscanf("123456abcdedfBCDEF", "%[^A-Z]", buf);

  printf("%s\n", buf);

  结果为:123456abcdedf

  6、给定一个字符串iios/12DDWDFF@122,获取 / 和 @ 之间的字符串,先将 "iios/"过滤掉,再将非'@'的一串内容送到buf中

  sscanf("iios/12DDWDFF@122", "%*[^/]/%[^@]", buf);

  printf("%s\n", buf);

  结果为:12DDWDFF

  7、给定一个字符串"hello, world",仅保留world。(注意:","之后有一空格,%s遇空格停止,加*则是忽略第一个读到的字符串)

  sscanf("hello, world", "%*s%s", buf);

  printf("%s\n", buf);

  结果为:world

  %*s表示第一个匹配到的%s被过滤掉,即hello被过滤了

  如果没有空格则结果为NULL。

  sscanf的功能很类似于正则表达式, 但却没有正则表达式强大,所以如果对于比较复杂的字符串处理,建议使用正则表达式.

  //-------------------------------------------------------

  用它来分隔类似这样的字符串2006:03:18:

  int a, b, c;

  /*sscanf("2006:03:18", "%d:%d:%d", a, b, c); */ /*错误方法, 要在变量a,b,c前加上取地址符, modified by huanmie_09*/

  sscanf("2006:03:18", "%d:%d:%d", &a, &b, &c);

  以及2006:03:18 - 2006:04:18:

  char sztime1[16] = "", sztime2[16] = "";

  sscanf("2006:03:18 - 2006:04:18", "%s - %s", sztime1, sztime2);

  但是后来,我需要处理2006:03:18-2006:04:18

  仅仅是取消了‘-’两边的空格,却打破了%s对字符串的界定。

  我需要重新设计一个函数来处理这样的情况?这并不复杂,但是,为了使所有的代码都有统一的风格,我需要改动很多地方,把已有的sscanf替换成我自己的分割函数。我以为我肯定需要这样做,并伴随着对sscanf的强烈不满而入睡;一觉醒来,发现其实不必。

  format-type中有%[]这样的type field。如果读取的字符串,不是以空格来分隔的话,就可以使用%[]。

  %[]类似于一个正则表达式。[a-z]表示读取a-z的所有字符,[^a-z]表示读取除a-z以外的所有字符。

  所以那个问题也就迎刃而解了:

  sscanf("2006:03:18 - 2006:04:18", "%[0-9,:] - %[0-9,:]", sztime1, sztime2);

  在softmse (Jake) 的问题贴http://community.csd(去掉我)n.n(去掉我)et/Expert/topic/4843/4843294.xml?temp=.4321558中 ,给出了一个很cool的sscanf用例,而后通过学习,发现sscanf真棒,现做一总结。

  原问题:

  iios/12DDWDFF@122

  获取/和@之间的字符串怎么做

  C程序里面有什么函数吗?

  代码:

  #include <stdio.h>

  int main()

  {

  const char* s = "iios/12DDWDFF@122";

  char buf[20];

  sscanf( s, "%*[^/]/%[^@]", buf );

  printf( "%s\n", buf );

  return 0;

  }

  结果为:12DDWDFF


strtok()函数

http://baike.baidu.com/view/1028553.htm


原型:

char *strtok(char *s, const char *delim);

功能:

分解字符串为一组字符串。s为要分解的字符串,delim为分隔符字符串。


atoi()函数

http://baike.baidu.com/view/653935.htm

 C语言库函数名: atoi

  功 能: 把字符串转换成整型数.

  名字来源:array to integer 的缩写.

  原型: int atoi(const char *nptr);

  函数说明: 参数nptr字符串,如果第一个非空格字符不存在或者不是数字也不是正负号则返回零,否则开始做类型转换,之后检测到非数字(包括结束符 \0) 字符时停止转换,返回整型数。

  头文件: #include <stdlib.h>

  程序例:

  1)

  #include <stdlib.h>

  #include <stdio.h>

  int main(void)

  {

  int n;

  char *str = "12345.67";

  n = atoi(str);

  printf("string = %s integer = %d\n", str, n);

  return 0;

  }

  执行结果

  string = 12345.67 integer = 12345

  2)

  #include <stdlib.h>

  #include <stdio.h>

  int main()

  {

  char a[] = "-100" ;

  char b[] = "123" ;

  int c ;

  c = atoi( a ) + atoi( b ) ;

  printf("c = %d\n", c) ;

  return 0;

  }

  执行结果

  c = 23

  简单的实现atoi函数源代码:

  #include <cctype>

  int my_atoi(const char* p){

  assert(p != NULL);

  bool neg_flag = false;// 符号标记

  int res = 0;// 结果

  if(p[0] == '+' || p[0] == '-')

  neg_flag = (*p++ != '+');

  while(isdigit(*p)) res = res*10 + (*p++ - '0');

  return neg_flag ?0 -res : res;

  }


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值