之前找实习,面试官给的几道面试题,分享一下我的具体做法。
1. 给一串数,把其中多余的空格去掉,比如“I am leader”,输出的结果是“I am leader”,要求占用内存最小,速度最快。
分析:
要求占用内存最小,肯定要求循环次数最少,拷贝字符串次数最少,至于循环次数的话,我们只想循环一次,至于怎么做呢?我们可以判断空格后面是否还有空格,如果有的话,我们在这里做一个标记mark,利用另外一个标记k记录有多少个多余空格,直到遇到不是空格的字符,这里的关键在于如何判断连续的空格,以及如何越过,关键问题是这个条件怎么写?如果遇到一个空格,假设他的下标是i,我们用while循环挨个去判断接下来有多少空格,累计共k个空格,那怎么把这些空格复制到前面呢?
源码实现:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int pickout(char *data, int length) {
int mark = 0;
int spaces = 0;
int i;
for (i = 0; i < length; i++) {
if (data[i] == ' ') {
spaces++;
} else {
spaces = 0;
}
if (spaces < 2) {
if (mark != i) {
data[mark] = data[i];
}
mark++;
}
}
data[mark] = '\0';
return mark;
}
int main(void) {
char data[] = "I am leader h! as ASD";
int length = strlen(data);
pickout(data, length);
printf("%s\n", data);
return 0;
}
另外一种实现:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int pickout(char*data, int length) {
int i, k;
int mark;
for (i = 0, mark = 0; i < length; i++) {
if (data[i] == ' ') {
k = 0;
while (data[i + k + 1] == ' ') {
k++;
}
if (k > 0) {
i = i + k;
}
}
if (i > mark) {
data[mark] = data[i];
}
mark++;
}
data[mark] = '\0';
return 0;
}
int main(void) {
char data[] = "I am leader h! as ASD";
int length = strlen(data);
pickout(data, length);
printf("%s\n", data);
return 0;
}
输出结果是
I am leader h! as ASD
由于只循环一次,所以计算复杂度是n。
2. 给两串按照升序排序好的数列,要求只利用一个循环找出它们中相同的个数,要求占用内存最小,算法复杂度最小。
源码实现:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int CalSameNum(int *data1, int length1, int *data2, int length2) {
int i = 0, j = 0;
int count = 0;
if (data1[0] > data2[length2 - 1] || data1[length1 - 1] < data2[0]) {
return count;
}
while (i < length1 && j < length2) {
while (data1[i] > data2[j]) {
j++;
}
if (data1[i] == data2[j]) {
count++;
j++;
}
i++;
}
return count;
}
int main(void) {
int data1[] = { 1, 3, 5, 6, 9, 10, 12, 24, 45, 46 };
int data2[] = { 1, 4, 6, 7, 9, 12, 32, 45, 46, 50, 102, 345 };
int length1 = sizeof(data1) / sizeof(int);
int length2 = sizeof(data2) / sizeof(int);
int num = 0;
num = CalSameNum(data1, length1, data2, length2);
printf("%d\n", num);
return 0;
}
输出结果是:
6
由于只循环一次,所以计算复杂度是n。
3. 给一串数,它们除以4取余,按照余数的大小排列,比如10,3,32,45,65,12...,取余是2,3,0,1,1,0...,那排序的结果是32,12,45,65,10,3...,要求算法复杂度最低。他的复杂度是nlg(n)么?还能否提高?
4. 要求把源码中的注释去掉,比如'/* */',以及“//”。
大体上是字符串匹配。
源代码如下(linux平台):
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <assert.h>
#include <sys/mman.h>
int EraseNotes(char *path){
int fdin;
int size = 0, i = 0, mark = 0, p = 0;
char *str = NULL;
struct stat statbuf;
if ((fdin = open(path, O_RDWR)) == -1) {
printf("no such file!\n");
return 1;
}
assert(fstat(fdin, &statbuf) == 0);
//获取文件大小
size = statbuf.st_size;
//把c文件map到内存中。
str = (char *) mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fdin, 0);
if (str == MAP_FAILED ) {
printf("map failed!\n");
return 1;
}
// printf("%s\n", str);
for (i = 0; i < size; i++) {
if (str[i] == '/' && str[i + 1] == '*') {
mark = 1;
p = i;
} else if (str[i] == '/' && str[i + 1] == '/') {
mark = 2;
p = i;
}
if (mark == 1) {
if ((str[i] == '*' && str[i + 1] == '/')) {
memset(str + p, ' ', i - p + 2);
mark = 0;
}
} else if (mark == 2) {
if (str[i] == 0xa) {
memset(str + p, ' ', i - p + 1);
mark = 0;
}
}
}
printf("%s\n", str);
//call of mmap
munmap(str, size);
close(fdin);
return 0;
}
int main(void) {
char *path = "123";
EraseNotes(path);
return 0;
}
123文件中的内容是
//as/
/*
*
*
* as
*/
main()
as
12
//as
//asddasd
/*
*
*/
输出结果是
main()
as
12