几道面试题,附源码(待续)

之前找实习,面试官给的几道面试题,分享一下我的具体做法。

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
                        


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值