1 条题解
-
0
题意分析
本题要求实现一个扩展的正常顺序字符串比较函数,用于处理包含数字、正负号和字母的字符串排序。核心规则如下:
- 大小写不敏感:比较时将字母统一视为大写(如
xYz
和XYz
视为相同)。 - 数字序列作为整体处理:连续的数字(包括前导的
+
/-
,但需满足符号前无数字)视为一个数值,按数值大小比较(如100
大于2
,-3
小于1
)。 - 符号与数字的结合规则:若
+
/-
前无数字,则视为后续数字的符号(如A+003
等同于A3
,123+456
中的+
分隔两个数字)。
输入输出要求:
- 输入多个测试用例,每个用例包含两个字符串,输出比较结果(
-1
、0
、1
),分别表示第一个字符串应排在第二个之前、相同、之后。
解题思路
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. 逐令牌比较
按顺序比较两个字符串的令牌:
- 类型不同:数字令牌(数值)始终小于字符令牌(字符)。例如:
"a1"
(字符+数字)小于"aA"
(字符+字符),因为数字令牌<
字符令牌。 - 类型相同:
- 字符令牌:按大写字符的 ASCII 码顺序比较(如
'A'
<'B'
)。 - 数字令牌:按数值大小比较(如
-3
<1
,100
>2
)。
- 字符令牌:按大写字符的 ASCII 码顺序比较(如
- 长度不等:若前
n
个令牌均相同,较短的字符串更小(类似字典序,如"abc"
<"abcd"
)。
实现步骤
1. 分词函数设计
使用正则表达式或双指针法遍历字符串,识别数字令牌和字符令牌:
- 双指针法:
- 初始化指针
i
从字符串开头开始。 - 若当前字符是数字,或前一个字符是数字且当前是
+
/-
(如123+456
中的+
属于下一个数字令牌),则扩展数字令牌至连续数字和符合规则的符号。 - 否则,作为单个字符令牌处理,转为大写。
- 初始化指针
2. 令牌比较逻辑
- 对两个字符串生成令牌列表
tokens_a
和tokens_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
。
代码实现要点
- 分词逻辑:确保符号正确归属数字令牌,避免误判(如
123+456
拆分为两个数字令牌,A+123
拆分为字符和数字令牌)。 - 令牌转换:数字令牌需处理前导零和符号,转换为整数;字符令牌统一转为大写。
- 逐令牌比较:按规则处理类型不同和类型相同的情况,最后处理长度差异。
通过以上步骤,可将复杂的字符串比较问题拆解为结构化的令牌比较,确保符合题目要求的扩展正常顺序排序规则。
#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
- 上传者