带通配符的字符串匹配问题


  1. 字符串匹配问题,给定一串字符串,按照指定规则对其进行匹配,并将匹配的结果保存至output数组中,多个匹配项用空格间隔,最后一个不需要空格。


    要求:


  2. 匹配规则中包含通配符?和*,其中?表示匹配任意一个字符,*表示匹配任意多个(>=0)字符。
  3. 匹配规则要求匹配最大的字符子串,例如a*d,匹配abbdd而非abbd,即最大匹配子串。
  4. 匹配后的输入串不再进行匹配,从当前匹配后的字符串重新匹配其他字符串。


    请实现函数:


      char* my_find(char input[], char rule[])


    举例说明:



    注意事项:

    1. 自行实现函数my_find,勿在my_find函数里夹杂输出,且不准用C、C++库,和Java的String对象;

    2. 请注意代码的时间,空间复杂度,及可读性,简洁性;

    3. input=aaa,rule=aa时,返回一个结果aa,即可。

     

     

    解法一


    本题与上述第三十章的题不同,上题字符串转换成整数更多考察对思维的全面性和对细节的处理,本题则更多的是编程技巧。闲不多说,直接上代码:


    //copyright@cao_peng 2013/4/23
    int str_len(char *a)
    {
       
    //字符串长度
       
    if (a == 0)
        {
           
    return 0;
        }
       
    char *t = a;
       
    for (; *t; ++t)
            ;
       
    return (int) (t - a);
    }

    void str_copy(char *a, const char *b, int len)
    {
       
    //拷贝字符串 a = b
       
    for (; len > 0; --len, ++b, ++a)
        {
           
    *a = *b;
        }
       
    *a = 0;
    }

    char *str_join(char *a, const char *b, int lenb)
    {
       
    //连接字符串 第一个字符串被回收
       
    char *t;
       
    if (a == 0)
        {
            t
    = (char *) malloc(sizeof(char) * (lenb + 1));
            str_copy(t, b, lenb);
           
    return t;
        }
       
    else
        {
           
    int lena = str_len(a);
            t
    = (char *) malloc(sizeof(char) * (lena + lenb + 2));
            str_copy(t, a, lena);
           
    *(t + lena) = ' ';
            str_copy(t
    + lena + 1, b, lenb);
            free(a);
           
    return t;
        }
    }

    int canMatch(char *input, char *rule)
    {
       
    // 返回最长匹配长度 -1表示不匹配
       
    if (*rule == 0)
        {
           
    //已经到rule尾端
           
    return 0;
        }
       
    int r = -1 , may;
       
    if (*rule == '*')
        {
            r
    = canMatch(input, rule + 1);  // *匹配0个字符
           
    if (*input)
            {
                may
    = canMatch(input + 1, rule);  // *匹配非0个字符
               
    if ((may >= 0) && (++may > r))
                {
                    r
    = may;
                }
            }
        }
       
    if (*input == 0)
        {
           
    //到尾端
           
    return r;
        }
       
    if ((*rule == '?') || (*rule == *input))
        {
            may
    = canMatch(input + 1, rule + 1);
           
    if ((may >= 0) && (++may > r))
            {
                r
    = may;
            }
        }
       
    return r;
    }

    char * my_find(char input[], char rule[])
    {
       
    int len = str_len(input);
       
    int *match = (int *) malloc(sizeof(int) * len);  //input第i位最多能匹配多少位 匹配不上是-1
       
    int i, max_pos = - 1;
       
    char *output = 0;

       
    for (i = 0; i < len; ++i)
        {
            match[i]
    = canMatch(input + i, rule);
           
    if ((max_pos < 0) || (match[i] > match[max_pos]))
            {
                max_pos
    = i;
            }
        }
       
    if ((max_pos < 0) || (match[max_pos] <= 0))
        {
           
    //不匹配
            output
    = (char *) malloc(sizeof(char));
           
    *output = 0;   // \0
           
    return output;
        }
       
    for (i = 0; i < len;)
        {
           
    if (match[i] == match[max_pos])
            {
               
    //找到匹配
                output
    = str_join(output, input + i, match[i]);
                i
    += match[i];
            }
           
    else
            {
               
    ++i;
            }
        }
        free(match);
       
    return output;
    }

     

     

    解法二、动态规划


    本题也可以直接写出DP(Dynamic Programming, 动态规划)方程,如下代码所示:


    //copyright@chpeih 2013/4/23
    char* my_find(char input[], char rule[])
    {
       
    //write your code here
       
    int len1, len2;
       
    for (len1 = 0; input[len1]; len1++);
       
    for (len2 = 0; rule[len2]; len2++);
       
    int MAXN = len1 > len2 ? (len1 + 1) : (len2 + 1);
       
    int  **dp;

       
    //dp[i][j]表示字符串1和字符串2分别以i j结尾匹配的最大长度
       
    //记录dp[i][j]是由之前那个节点推算过来  i*MAXN+j
        dp
    = new int *[len1 + 1];
       
    for (int i = 0; i <= len1; i++)
        {
            dp[i]
    = new int[len2 + 1];

        }

        dp[
    0][0] = 0;
       
    for (int i = 1; i <= len2; i++)
            dp[
    0][i] = -1;
       
    for (int i = 1; i <= len1; i++)
            dp[i][
    0] = 0;

       
    for (int i = 1; i <= len1; i++)
        {
           
    for (int j = 1; j <= len2; j++)
            {
               
    if (rule[j - 1] == '*')
                {
                    dp[i][j]
    = -1;
                   
    if (dp[i - 1][j - 1] != -1)
                    {
                        dp[i][j]
    = dp[i - 1][j - 1] + 1;

                    }
                   
    if (dp[i - 1][j] != -1 && dp[i][j] < dp[i - 1][j] + 1)
                    {
                        dp[i][j]
    = dp[i - 1][j] + 1;
                    }
                }
               
    else if (rule[j - 1] == '?')
                {
                   
    if (dp[i - 1][j - 1] != -1)
                    {
                        dp[i][j]
    = dp[i - 1][j - 1] + 1;

                    }
                   
    else dp[i][j] = -1;
                }
               
    else
                {
                   
    if (dp[i - 1][j - 1] != -1 && input[i - 1] == rule[j - 1])
                    {
                        dp[i][j]
    = dp[i - 1][j - 1] + 1;
                    }
                   
    else dp[i][j] = -1;
                }
            }
        }

       
    int m = -1;//记录最大字符串长度
       
    int *ans = new int[len1];
       
    int count_ans = 0;//记录答案个数
       
    char *returnans = new char[len1 + 1];
       
    int count = 0;
       
    for (int i = 1; i <= len1; i++)
           
    if (dp[i][len2] > m)
            {
                m
    = dp[i][len2];
                count_ans
    = 0;
                ans[count_ans
    ++] = i - m;
            }
           
    else if (dp[i][len2] != -1 && dp[i][len2] == m)
            {
                ans[count_ans
    ++] = i - m;
            }

       
    if (count_ans != 0)
        {
           
    int len = ans[0];
           
    for (int i = 0; i < m; i++)
            {
                printf(
    "%c", input[i + ans[0]]);
                returnans[count
    ++] = input[i + ans[0]];
            }
           
    for (int j = 1; j < count_ans; j++)
            {
                printf(
    " ");
                returnans[count
    ++] = ' ';
                len
    = ans[j];
               
    for (int i = 0; i < m; i++)
                {
                    printf(
    "%c", input[i + ans[j]]);
                    returnans[count
    ++] = input[i + ans[j]];
                }
            }
            printf(
    "\n");
            returnans[count
    ++] = '\0';
        }

       
    return returnans;
    }

     

    Pasted from <https://github.com/julycoding/The-Art-Of-Programming-By-July/blob/master/ebook/zh/01.03.md>

     

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值