华为今年软开提前批招聘的特别早,从7月中旬就开始了,广大IT屌丝们表示普遍没有心理准备啊~~华为软开校招共分三轮,第一轮是上机测试,一共3个编程题,满分320分,初级题(60分)、中级题(100分)、高级题(160分),做出一道题即可进入下一轮(中间还有个性格测试题,不过绝大部分人都能过),第二题是一道字符串处理题(貌似华为每年机试题目里,大都会有一道字符串处理的题目),题目大概是这样的:
给定一个字符串str,比如:gyreabtcdgkljnzab,该字符串由用户在控制台自己输入,然后接着用户输入替换组数m,比如m=2,然后用户根据前面的组数输入替换字符串,输入格式可如下:ab->abcd,每个输入之间独占一行。最后程序输出替换后的字符,比如:组1:经过ab->abcd后,源字符串变为:gyreabcdtcdgkljnzabcd,组2:经过dt->kb后,源字符串变为:gyreabckbcdgkljnzabcd,于是最终输出:gyreabckbcdgkljnzabcd。示例:
input:
gyreabtcdgkljnzab
2
ab->abcd
dt->kb
output:
gyreabckbcdgkljnzabcd
一、C语言解法
思路:利用字符数组src将源字符串存储下来,根据输入的替换组数m,动态声明3个二维字符数组str3[m][]、str1[m][]、str2[m][],一个用于存储替换
字符,一个用于存储被替换的字符串,一个存储替换后的字符串,如对于替换字符串str3[1][] = "ab->abcd",则str1[1] = "ab",str2[1] = "abcd"。
具体代码及注释如下:
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void splitStr( char *src, char *dst1, char *dst2 );
int strReplace( char *src, char *dst, char **str1, char **str2, const int num );
int _tmain(int argc, _TCHAR* argv[])
{
char src[300] = {'\0'}; // 源字符串
char dst[300] = {'\0'}; // 目的字符串
int m = 0; // 替换组数
char **str3 = NULL; // 替换字符串
int i = 0;
char **str1 = NULL, **str2 = NULL;
// 获取源字符串
gets( src );
// 获取替换组数
scanf( "%d", &m );
getchar(); // 此时换行符留在stdin缓冲区中,必须将其读取,接着一条gets语句接收将是换行符
// 动态申请内存,为拆分替换字符串做准备
str1 = (char **)malloc( sizeof(char *)*m );
str2 = (char **)malloc( sizeof(char *)*m );
str3 = (char **)malloc( sizeof(char *)*m );
for( i=0; i<m; i++ )
{
*(str1+i) = (char *)malloc( 30 );
*(str2+i) = (char *)malloc( 30 );
*(str3+i) = (char *)malloc( 30 );
memset( *(str1+i), 0, 30 );
memset( *(str2+i), 0, 30 );
memset( *(str3+i), 0, 30 );
gets( *(str3+i) ); // 获取替换字符串
splitStr( *(str3+i), *(str1+i), *(str2+i) ); // 拆分替换字符串
}
// 对源字符串进行替换处理
if( 0 == strReplace( src, dst, str1, str2, m ) )
puts( dst );
system( "pause" );
for( i=0; i<m; i++ )
{
free( *(str1+i) );
free( *(str2+i) );
free( *(str3+i) );
}
free( str1 );
free( str2 );
free( str3 );
str1 = NULL;
str2 = NULL;
str3 = NULL;
return 0;
}
/**************************************************************************************
说明:对字符串进行分割操作一般采用strtok库函数进行处理,但是此处考虑到分隔符为“->”为一个子串,因而
使用了strstr函数进行处理。
另外此处还可以使用for循环 + strncmp函数进行分隔操作,代码如下:
int len = strlen(src);
int j = 0, k = 0;
for( int i=0; i<len; i++ )
{
if( 0 == strncmp( src, "->", 2 ) )
{
strcpy( dst2, src+i );
}
else
{
*(dst1+j) = *(src+i);
}
}
* Author: Sky
* Date: 2014/08/01
* Functiuon: splitStr
* Description: 对源字符串进行拆分操作
* Access Level: N
* Input: src ---- 源字符串 (ab->abcd)
* Output: dst1 --- 拆分子串1(ab)
dst2 --- 拆分子串2(abcd)
* Return: NULL
**************************************************************************************/
void splitStr( char *src, char *dst1, char *dst2 )
{
int i = 0;
char *pos = NULL;
pos = strstr( src, "->" ); // “->”在字符串中的位置
strncpy( dst1, src, pos-src);
strcpy( dst2, pos+2);
}
/**************************************************************************************
* Author: Sky
* Date: 2014/08/01
* Functiuon: strReplace
* Description: 字符串替换函数,将源字符串src中的子串str1替换成子串str2
* Access Level: N
* Input: src --------- 源字符串
str1 -------- 被替换子串
str2 -------- 替换后的子串
m ----------- 替换组数
* Output: dst --------- 目的字符串(替换子串后的源字符串)
* Return: 0/-1 成功/失败
**************************************************************************************/
int strReplace( char *src, char *dst, char **str1, char **str2, const int m )
{
int i = 0, j = 0;
int k = 0; // 目的串当前指针位置
int len = 0, sublen1 = 0, sublen2 = 0;
if( NULL == src )
return -1;
for( i=0; i<m; i++ ) // 外层循环控制替换组数也即替换轮数
{
len = strlen( src );
for( j=0; j<len; j++ ) // 内层循环控制当前轮次字符串的替换
{
sublen1 = strlen( str1[i] );
if( 0 == strncmp( src+j, str1[i], sublen1 ) ) // 如果当前匹配
{
sublen2 = strlen( str2[i] );
strncpy( dst+k, str2[i], sublen2 ); // 替换源字符串中的子串
k += sublen2;
j += sublen1-1;
}
else // 否则
{
*(dst+k) = *(src+j);
k++;
}
}
*(dst+k) = '\0';
k = 0; // 一轮替换完成,为新一轮替换复位
strcpy( src, dst );
}
return 0;
}
运行结果图:
顺便说一说圈复杂度,面试的时候面试官问头圈复杂度是个什么东东?我没答上来,回来我查了一下,下面是引用CSDN的一篇博文:原地址:http://blog.csdn.net/horkychen/article/details/6996847,大家也可以再维基百科中直接搜索关键字“循环复杂度”
圈复杂度用来评价代码复杂度,以函数为单位,数值越大表示代码的逻辑分支越多,理解起来也更复杂。圈复杂度可以成为编码及重构的重要参考指标,以指导撰写可读性高的代码。有关圈复杂度的定义,可以自行搜索。《代码大全》有如下的定义:
计算子程序中决策点数量的技术 (代码大全2,19章P458)
1.由1计数,一直往下通过程序。
2.一旦遇到以下关键字,或者其同类的词,就加1:
if, while, repeat, for, and, or
3. 给case(switch)语句中的每一种情况都加1.
作者也给了处理复杂度度量结果的建议:
0-5: 子程序可能还不错
6-20: 得想办法简化子程序了
10+ 把子程序的某一部分拆分成另一个子程序并调用它。
这些数字和策略都不是绝对的,正如作者所言至少应当视其为警示。