• 字符串压缩问题


    字符串压缩问题——程序员解法

    字符串压缩问题——程序员解法

     

      在http://www.cnblogs.com/bestDavid/p/Stringeliminate.html看到了一个有趣的小题:

    给定一个字符串,仅由a,b,c 3种小写字母组成。当出现连续两个不同的字母时,你可以用另外一个字母替换它。
    如有ab或ba连续出现,你把它们替换为字母c;
    有ac或ca连续出现时,你可以把它们替换为字母b;
    有bc或cb连续出现时,你可以把它们替换为字母a。
    你可以不断反复按照这个规则进行替换,你的目标是使得最终结果所得到的字符串尽可能短,求最终结果的最短长度。
    输入:字符串。长度不超过200,仅由abc三种小写字母组成。
    输出:按照上述规则不断消除替换,所得到的字符串最短的长度。
    例如:
    输入cab,输出2。因为我们可以把它变为bb或者变为cc。          
    输入bcab,输出1。尽管我们可以把它变为aab -> ac -> b,也可以把它变为bbb,但因为前者长度更短,所以输出1。

      这个题目原博文中是用“数学”的方法给出解答的,但其推理证明过程(包括引文给出的证明过程)并不严谨,结论依据不足。所以这里用程序员的思考方法给出解答。

      程序员的方法无非就是老老实实地进行替换。对每一种可以替换的情形都进行替换。例如对bcab,可以替换为aab,bbb和bcc。题中提到“可以不断反复按照这个规则进行替换”,所以上面的各个情况又可以进一步
      aab:
      aab->ac->b 长度为1.
      bbb:
      无不同字母,无法进一步替换。长度为3
      bcc:
      bcc->ac->b 长度为1
      综上,对bcab进行不断变换,所得到的字符串的最短长度为1。
      因此,很容易给出代码总体结构。 

    复制代码
     1 #include <stdio.h>
     2 
     3 #define MAX 200
     4 
     5 typedef char String[ MAX + 1 ];
     6 
     7 #define N(x) N_(x)
     8 #define N_(x) #x
     9 
    10 void input( char * );
    11 unsigned min_len( char * );
    12 
    13 int main( void )
    14 {
    15    String str;  
    16    
    17    input( str );
    18 
    19    printf("替换最终结果的最短长度为%u。
    " , min_len( str ) );
    20 
    21    return 0;
    22 }
    23 
    24 unsigned min_len( char *s )
    25 {
    26    
    27 }
    28 
    29 void input( char *s )
    30 {
    31    puts("输入字符串");
    32    scanf("%"N(MAX)"[abc]s",s);
    33    puts("要确定长度的字符串为:");
    34    puts( s );
    35 }
    复制代码

       其中宏 MAX 为字符串初始最大长度,为了给字符串结尾的留出空间,存储字符串的字符数组的最大尺寸为 MAX + 1 。由于这种类型在整个代码中频繁用到,所以用 typedef 为其取了一个统一的名字。
      函数input()输入字符串由于字符串由a、b、c三种字母组成,所以禁止输入其他字符这就是 scanf("%"N(MAX)"[abc]s",s); 中[abc]的目的。又考虑到防止数组输入越界,因此为输入增加了宽度限制——N(MAX),宏展开后的结果为"200"。所以"%"N(MAX)"[abc]s"就是"%200[abc]s"。

      下面考虑min_len( char *s )函数。基本思路就是先求出s的初始长度

    int len = strlen( s );

      然后从头至尾检查是否有相邻的相异字符,如有则替换:

    reduce( newstr , s , i1 );

      这样将得到一个新的字符串newstr。设新字符串的长度为

    int newlen ;

      新字符串最终长度显然仍然可以用min_len()求得:

    newlen = min_len( newstr );

      如果newlen小于len,则将len记为newlen的值。

             if ( newlen < len )
             {
                len = newlen ;
             }

      这样返回最后的len就是变换后的最短长度。min_len函数完整代码如下:

    复制代码
     1 unsigned min_len( char *s )
     2 {
     3    int len = strlen( s );
     4    int i = 0 ;
     5    while ( s[i] != '' && s[i+1] != '' )
     6    {
     7       if ( s[i] != s[i+1] )
     8       {
     9          String newstr ;
    10          unsigned newlen ;
    11          
    12          reduce( newstr , s , i );
    13          newlen = min_len( newstr );
    14          if ( newlen < len )
    15          {
    16             len = newlen ;
    17          }
    18       }
    19       i ++ ;
    20    }
    21    return len;
    22 }
    复制代码

      再来看一下reduce()函数。完成三件事:

    1. 将ss[i]前面的字符——一共i个,copy到st中:strncpy( st , ss , i );
    2. 根据ss[i],ss[i+1]求出替换字符,并写到st[i]中。
    3. 将ss中ss[i+1]以后的部分copy到st中从st[i+1]开始的位置。

      至此,问题解决,全部代码完成。下面是完整的代码。

    复制代码
     1 #include <stdio.h>
     2 #include <string.h>
     3 
     4 #define MAX 200
     5 
     6 typedef char String[ MAX + 1 ];
     7 
     8 #define N(x) N_(x)
     9 #define N_(x) #x
    10 
    11 void input( char * );
    12 unsigned min_len( char * );
    13 void reduce( char * , char * , unsigned );
    14 char turn ( char , char );
    15 
    16 int main( void )
    17 {
    18    String str;  
    19    
    20    input( str );
    21 
    22    printf("替换最终结果的最短长度为%u。
    " , min_len( str ) );
    23    
    24    return 0;
    25 }
    26 
    27 char turn ( char c1 , char c2 )
    28 {
    29    return 'a' + 'b' + 'c' - c1 - c2 ;
    30 }
    31 
    32 void reduce( char * st , char * ss , unsigned i )
    33 {
    34    strncpy( st , ss , i );
    35    st[i] = turn ( ss[i] , ss[i+1] );
    36    strcpy( st + i + 1 , ss + i + 2 );
    37 }
    38 
    39 unsigned min_len( char *s )
    40 {
    41    int len = strlen( s );
    42    int i = 0 ;
    43    while ( s[i] != '' && s[i+1] != '' )
    44    {
    45       if ( s[i] != s[i+1] )
    46       {
    47          String newstr ;
    48          unsigned newlen ;
    49          
    50          reduce( newstr , s , i );
    51          newlen = min_len( newstr );
    52          
    53          if ( newlen < len )
    54             len = newlen ;
    55       }
    56       i ++ ;
    57    }
    58    return len;
    59 }
    60 
    61 void input( char *s )
    62 {
    63    puts("输入字符串");
    64    scanf("%"N(MAX)"[abc]s",s);
    65    
    66    puts("要确定长度的字符串为:");
    67    puts( s );
    68 }
    复制代码
     
     
     
    标签: C语言递归字符串
  • 相关阅读:
    Xshell 使用纪要
    矩阵求逆
    Ubuntu 增加新用户
    matlab 常用图像处理
    Surface Evolver 基本操作、使用指南和珍贵资料
    latex 裁剪图片
    Inkscape 输入希腊字母
    Pyton——int内部功能介绍
    python——登陆接口设计(循环方法)
    Python之三层菜单
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3293796.html
Copyright © 2020-2023  润新知