1 条题解

  • 0
    @ 2025-5-28 16:03:33

    题意分析

    本题要求实现一个扩展的正常顺序字符串比较函数,用于处理包含数字、正负号和字母的字符串排序。核心规则如下:

    1. 大小写不敏感:比较时将字母统一视为大写(如 xYzXYz 视为相同)。
    2. 数字序列作为整体处理:连续的数字(包括前导的 +/-,但需满足符号前无数字)视为一个数值,按数值大小比较(如 100 大于 2-3 小于 1)。
    3. 符号与数字的结合规则:若 +/- 前无数字,则视为后续数字的符号(如 A+003 等同于 A3123+456 中的 + 分隔两个数字)。

    输入输出要求

    • 输入多个测试用例,每个用例包含两个字符串,输出比较结果(-101),分别表示第一个字符串应排在第二个之前、相同、之后。

    解题思路

    1. 字符串分词(Tokenization)

    将字符串拆分为数字令牌字符令牌,规则如下:

    • 数字令牌:连续的数字序列,可能以 +/- 开头(但前提是符号前无数字)。例如:
      • "x-3" 拆分为 ['x', '-3']'-' 前是字符 'x',故属于数字令牌)。
      • "123+456" 拆分为 ['123', '+456']'+' 前是数字 '123',故 '+' 分隔两个数字令牌)。
    • 字符令牌:单个非数字字符,统一转为大写(如 'a''Z' 均转为 'A''Z')。

    2. 令牌归一化

    • 数字令牌:转换为整数(忽略前导零,保留符号)。例如:
      • "003"3"+003"3"-0"0"0"0
    • 字符令牌:直接使用大写形式(如 'a''A')。

    3. 逐令牌比较

    按顺序比较两个字符串的令牌:

    1. 类型不同:数字令牌(数值)始终小于字符令牌(字符)。例如:"a1"(字符+数字)小于 "aA"(字符+字符),因为数字令牌 < 字符令牌。
    2. 类型相同
      • 字符令牌:按大写字符的 ASCII 码顺序比较(如 'A' < 'B')。
      • 数字令牌:按数值大小比较(如 -3 < 1100 > 2)。
    3. 长度不等:若前 n 个令牌均相同,较短的字符串更小(类似字典序,如 "abc" < "abcd")。

    实现步骤

    1. 分词函数设计

    使用正则表达式或双指针法遍历字符串,识别数字令牌和字符令牌:

    • 双指针法
      • 初始化指针 i 从字符串开头开始。
      • 若当前字符是数字,或前一个字符是数字且当前是 +/-(如 123+456 中的 + 属于下一个数字令牌),则扩展数字令牌至连续数字和符合规则的符号。
      • 否则,作为单个字符令牌处理,转为大写。

    2. 令牌比较逻辑

    • 对两个字符串生成令牌列表 tokens_atokens_b
    • 逐个比较对应位置的令牌:
      • 若类型不同,数字令牌 < 字符令牌。
      • 若类型相同,按字符 ASCII 或数字值比较。
    • 若所有对应令牌相等,长度较短的字符串更小。

    3. 处理边界情况

    • 前导零:数字令牌转换为整数时自动忽略前导零(如 "003"3)。
    • 符号规则:仅当前导符号前无数字时,符号属于数字令牌(如 "-3" 是数字令牌,"3-"- 是字符令牌)。
    • 空字符串:视为所有令牌为空,直接根据长度比较。

    示例分析

    输入x-3 X0001

    • 分词
      • x-3[('char', 'X'), ('num', -3)]
      • X0001[('char', 'X'), ('num', 1)]
    • 比较
      • 第一个令牌均为 'X',相等。
      • 第二个令牌:-3 < 1,故结果为 -1

    输入xYz000123J XyZ+123j

    • 分词
      • xYz000123J[('char', 'X'), ('char', 'Y'), ('char', 'Z'), ('num', 123), ('char', 'J')]
      • XyZ+123j[('char', 'X'), ('char', 'Y'), ('char', 'Z'), ('num', 123), ('char', 'J')]
    • 比较:所有令牌相等,结果为 0

    代码实现要点

    1. 分词逻辑:确保符号正确归属数字令牌,避免误判(如 123+456 拆分为两个数字令牌,A+123 拆分为字符和数字令牌)。
    2. 令牌转换:数字令牌需处理前导零和符号,转换为整数;字符令牌统一转为大写。
    3. 逐令牌比较:按规则处理类型不同和类型相同的情况,最后处理长度差异。

    通过以上步骤,可将复杂的字符串比较问题拆解为结构化的令牌比较,确保符合题目要求的扩展正常顺序排序规则。

    
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cctype>
    using namespace std;
     
    bool issign( char s[] , int i ) {
        return ( i == 0 || !isdigit( s[ i - 1] ) ) && ( s[ i ] == '+' || s[ i ] == '-' ) && isdigit( s[ i + 1 ] );
    }
     
    void formalize( char s[] ) {
        int i, j;
        static char temp[ 1000 ];
     
        for ( i = 0, j = 0; i < strlen( s ); i++, j++ ) {
            if ( isdigit( s[ i ] ) ) {
                if ( i == 0 || ( s[ i - 1 ] != '+' && s[ i - 1 ] != '-' ) )
                    temp[ j++ ] = '+';
                while ( s[ i ] == '0' )
                    i++;
                while ( isdigit( s[ i ] ) )
                    temp[ j++ ] = s[ i++ ];
                if ( temp[ j - 1 ] == '+' || temp[ j - 1 ] == '-' )
                    j--;
            }
            temp[ j ] = ( s[ i ] >= 'a' && s[ i ] <= 'z' ? s[ i ] - 32: s[ i ] );
        }
        temp[ j ] = '\0';
        strcpy( s, temp );
    }
     
    int cmp( char s1[], char s2[] ) {
        static int len1, len2;
     
        formalize( s1 );
        formalize( s2 );
        for ( int i = 1, j = 1; i < strlen( s1 ) && j < strlen( s2 ); i++, j++  ) {
            if ( isdigit( s1[ i ] ) && isdigit( s2[ j ] ) ) {
                int k = i;
                while ( isdigit( s1[ k ] ) )
                    k++;
                len1 = k - i;
                k = j;
                while ( isdigit( s2[ k ] ) )
                    k++;
                len2 = k - j;
     
                if ( len1 != len2 )
                    return ( len1 < len2 ? -1: 1 );
                else {
                    while ( i < k && j < k ) {
                        if ( s1[ i++ ] != s2[ j++ ] )
                            return ( s1[ i ] < s2[ j ] ? -1: 1 );
                    }
                }
            }
     
            if ( s1[ i ] != s2[ j ] ) {
                if ( issign( s1, i ) && issign( s2, j ) )
                    return ( s1[ i ] == '-' ? -1: 1 );
                return ( s1[ i ] < s2[ j ] ? -1: 1 );
            }
        }
     
        return 0;
     
    }
     
     
    int main()
    {
        int N, i;
        char s1[ 1000 ], s2[ 1000 ];
     
        cin >> N;
        for ( i = 1; i <= N; i++ ) {
            scanf( "%s%s", s1, s2 );
            cout << i << " " << cmp( s1, s2 ) <<  endl;
        }
     
        return 0;
     
    }                                 
    
    • 1

    信息

    ID
    2794
    时间
    1000ms
    内存
    256MiB
    难度
    (无)
    标签
    递交数
    0
    已通过
    0
    上传者