现在的位置: 首页 > 综合 > 正文

早上看到的微软笔试题,随便写个答案

2016年12月04日 ⁄ 综合 ⁄ 共 6615字 ⁄ 字号 评论关闭

微软十五道面试题

1、有一个整数数组,请求出两两之差绝对值最小的值,
记住,只要得出最小值即可,不需要求出是哪两个数。

这个我没找到高效算法,O(n2)算法很好实现,应该都能想到的,另外一个快一点点的就是先排序一下,然后查找最小差的,排序用快排可以在)O(nlg(n))内完成,然后查找可以在线性时间完成,总复杂度O(nlg(n))

2、写一个函数,检查字符是否是整数,如果是,返回其整数值。
(或者:怎样只用4行代码编写出一个从字符串到长整形的函数?)

int char2int(char c){
	if(c >= '0' || c<= '9')
		return c - '0';
	return -1;
}


3、给出一个函数来输出一个字符串的所有排列。

这个网上到处可以找到的

4、请编写实现malloc()内存分配函数功能一样的代码。 给出一个函数来复制两个字符串A和B。字符串A的后几个字节和字符串B的前几个字节重叠。

题目没看懂什么意思

5、怎样编写一个程序,把一个有序整数数组放到二叉树中?

排序的数组本身就可以当做是一颗排序二叉树,二分查找就是用这个特性的

struct tree_node{
	int data;
	struct tree_node* left;
	struct tree_node* right;
};

struct tree_node* array2tree(int* array, int start, int end){
	struct tree_node* ret;
	int mid;
	if(start > end)
		return 0;
	if(start == end){
		ret = (struct tree_node*)malloc(sizeof(*ret));
		ret->data = *(array + start);
		ret->left = ret->right = 0;
		return ret;
	}
	ret = (struct tree_node*)malloc(sizeof(*ret));
	mid = (start + end) / 2;
	ret->data = mid;
	ret->left = array2tree(array, start, mid - 1);
	ret->right = array2tree(array, mid + 1, end);
	return ret;
}

6、怎样从顶部开始逐层打印二叉树结点数据?请编程。  

这个就是经典的BFS了。

struct tree_node{
	int data;
	struct tree_node* left;
	struct tree_node* right;
};

void BFS(struct tree_node* root){
	queue<void*> bfs_queue;
	struct tree_node* iter;
	bfs_queue.push(root);
	while(!bfs.empty()){
		iter = (struct tree_node*)bfs_queue.pop();
		if(!iter)
			continue;
		printf("%d", iter->data);
		bfs_queue.push(iter->left);
		bfs_queue.push(iter->right);
	}
}

7、怎样把一个链表掉个顺序(也就是反序,注意链表的边界条件并考虑空链表)?

这个就保存连续的三个链表节点就可以反转单链表

struct list_node{
	int test;
	struct list_node* next;
};

struct list_node* reverse_list(struct list_node* head){
	struct list_node* cur, *next, *nnext;
	if(!head || !head->next)
		return head;
	cur = head;
	next = head->next;
	nnext = next->next;
	while(!next){
		next->next = cur;
		cur = next;
		next = nnext;
		if(nnext)
			nnext = nnext->next;
	}
	return cur;
}

8、请编写能直接实现int atoi(const char * pstr)函数功能的代码。

#define INT_MAX ~0x00
int atoi(char* pstr){
	int sign = 0, ret = 0, index = 0, iter = 0;
	int is_minus = 0;
	int* array = 0;
	if(!pstr || !strlen(pstr))
		return INT_MAX;
	array =	(int*)malloc(strlen(pstr));
	if(pstr[0] == '-'){
		sign = 1;
		is_minus = 1;
	}else if(pstr[0] == '+')
		sign = 1;
	else{
		int bit_int;
		while((bit_int = char2int(pstr[index + sign])) != -1){
			*(array + index) = bit_int;
			index ++;
		}
	}
	while(iter < index){
		ret += array[iter];
		ret *= 10;
	}
	if(is_minus)
		ret = 0 - ret;
	return ret;
}

9、编程实现两个正整数的除法
编程实现两个正整数的除法,当然不能用除法操作符。
// return x/y.
int div(const int x, const int y) 
{
  ....
}

这个随便找本算法的书上就有了,就不写了

10、在排序数组中,找出给定数字的出现次数
比如 [1, 2, 2, 2, 3] 中2的出现次数是3次。

二分查找,然后分别向前和向后找相同的值就行了

11、平面上N个点,每两个点都确定一条直线,
求出斜率最大的那条直线所通过的两个点(斜率不存在的情况不考虑)。时间效率越高越好。

这个没找到高效算法,不善于处理这种问题

12、一个整数数列,元素取值可能是0~65535中的任意一个数,相同数值不会重复出现。0是例外,可以反复出现。
请设计一个算法,当你从该数列中随意选取5个数值,判断这5个数值是否连续相邻。
注意:
- 5个数值允许是乱序的。比如: 8 7 5 0 6
- 0可以通配任意数值。比如:8 7 5 0 6 中的0可以通配成9或者4
- 0可以多次出现。
- 复杂度如果是O(n2)则不得分。

这个就是类似正则表达式的匹配了,0当做通配符就可以了

13、设计一个算法,找出二叉树上任意两个结点的最近共同父结点。
复杂度如果是O(n2)则不得分。

从一个节点的parent的另外的一颗子树找另一个节点就可以了,二叉树上的时间复杂度为O(n)

struct tree_node{
	int data;
	struct tree_node* parent;
	struct tree_node* left;
	struct tree_node* right;
};
int BFS(struct tree_node* root, struct tree_node* find); //改进一下BFS,当在子树root中找到了find节点就返回1,否则返回0
int is_right(struct tree_node* node){
	if(node->parent && node->parent->right == node)
		return 1;
	return 0;
}
int is_left(struct tree_node* node){
	if(node->parent && node->parent->left == node)
		return 1;
	return 0;
}
struct tree_node* nearest_parent(struct tree_node* one, struct tree_node* two){
	struct tree_node* iter;
	if(BFS(one, two))
		return one;
	if(BFS(two, one))
		return two;
	iter = one;
	while(1){
		if(is_left(iter)){
			if(iter->parent->right && BFS(iter->parent->right, two))
				return iter->parent;
			iter = iter->parent;
			continue;
		}
		if(is_right(one)){
			if(iter->parent->left && BFS(iter->parent->left, two))
				return iter->parent;
			iter = iter->parent;
			continue;
		}
		return iter; //iter是root节点
	}
}

14、一棵排序二叉树,令 f=(最大值+最小值)/2,

设计一个算法,找出距离f值最近、大于f值的结点。
复杂度如果是O(n2)则不得分。

排序二叉树上的最大值为树的最右边的节点,一直right下去就可以,最小值为最左边的节点,一直left下去就找到最小值,因此可以得到f。然后就在二叉树上找比f大的值且距离最小就可以了,这个复杂度应该为O(n)

float fvalue(struct tree_node* root){
	float left_most = 0;
	float right_most = 0;
	struct tree_node* iter = root;
	while(iter->left){
		left_most = iter->data;
		iter = iter->left;
	}
	iter = root;
	while(iter->right){
		right_most = iter->data;
		iter = iter->right;
	}
	return (left_most + right_most) / 2;
}

struct tree_node* nearest(struct tree_node* root){
	float f;
	struct tree_node* sub_root, *temp;
	float root_distance, sub_distance;
	f = fvalue(root);
	sub_root = root;
	if(!sub_root)
		return 0;
	//root的data比f小,则所有的左子树都小,检查右子树就可以了
	if(sub_root->data < f){
		return nearest(sub_root->right);
	}
	//比较左子树和根节点的距离,选择较小的
	root_distance = f - sub_root->data;
	temp = nearest(sub_root->left);
	if(!temp)
		return sub_root;
	sub_distance = f - temp->data;
	if(root_distance > sub_distance)
		return temp;
	return sub_root;
}

15、一个整数数列,元素取值可能是1~N(N是一个较大的正整数)中的任意一个数,相同数值不会重复出现。
设计一个算法,找出数列中符合条件的数对的个数,满足数对中两数的和等于N+1。
复杂度最好是O(n),如果是O(n2)则不得分

32、一个文件中有40亿个整数,每个整数为四个字节,内存为1GB,写出一个算法:求出这个文件里的整数里不包含的一个整数

上面第一个题用位图算法或者用哈希表就可以了,由于N比较大,就选择位图了,所占内存小,两种方法的时间复杂度都为O(n)

第二个只能用位图了,算了一下大概占内存400M

struct bitmap{
	unsigned int bits;
	unsigned char map[1];
};

struct bitmap* alloc_bitmap(int size)
{
	int aligned_size, total_size;
	struct bitmap* ret;
	if(size <= 0)
		return 0;
	aligned_size = (size + 8 * sizeof(char) - 1)>>(3 * sizeof(char)); //计算需要size位需要多少字节
	total_size = sizeof(bitmap) + aligned_size - 1;
	ret = (struct bitmap*)malloc(total_size);
	if(!ret)
		exit(0);
	memset(ret, 0, total_size);
	ret->bits = size;
	return ret;
}

void free_bitmap(struct bitmap* map){
	if(map)
		free(map);
}

void clear_bit(struct bitmap* map, int index){
	char c = 0;
	int main = 0, minor = 0;
	if(index >= map->bits)
		return;
	main = index >> (3 * sizeof(char)); //在map数组中的索引
	minor = index % (8 * sizeof(char));//在字节中的索引
	c = bitmap->map[main];
	c = c & ~(0x01 << minor);
	bitmap->map[main] = c;
}

void set_bit(struct bitmap* map, int index){
	char c = 0;
	int main = 0, minor = 0;
	if(index >= map->bits)
		return;
	main = index >> (3 * sizeof(char));
	minor = index % (8 * sizeof(char));
	c = bitmap->map[main];
	c = c | (0x01 << minor);
	bitmap->map[main] = c;
}

int is_set(struct bitmap* map, int index){
	char c = 0;
	int main = 0, minor = 0;
	if(index >= map->bits)
		return 0;
	main = index >> (3 * sizeof(char));
	minor = index % (8 * sizeof(char));
	c = bitmap->map[main];
	return c & (0x01 << minor);
}

void find_pair(int* array, int num){
	struct bitmap* map;
	int iter = 0;
	map = alloc_bitmap(num + 1); //由于是从1到N
	while(iter < num){ //建立索引表
		if(!is_set(map, array[iter]))
			set_bit(map, array[iter]);
		iter++;
	}
	iter = 0;
	while(iter < num){ //在索引表中搜索相加为N+1的数对
		if(is_set(map, array[iter]) && is_set(map, num + 1 - array[iter])){
			printf("(%d, %d)\n", array[iter], num + 1 - array[iter]);
			clear_bit(map, array[iter]);
			clear_bit(map, num + 1 - array[iter]);
		}
		iter++;
	}
}

下面是腾讯的一两题,随便写写吧

33、腾讯服务器每秒有2w个QQ号同时上线,找出5min内重新登入的qq号并打印出来。

struct qq_list_hashtable{
	unsigned long qq;
	unsigned long timestamp;
	struct qq_list_hashtable *next, *prev;
	struct qq_list_hashtable *hnext, *hprev;
};

struct hash_head{
	struct qq_list_hashtable* next;
};

#define QQ_HASH_SIZE 11369 //最好使用素数,可以尽量均横的在哈希表上分布,避免某些地方碰撞次数特别多
struct hash_head[QQ_HASH_SIZE];

int hash_fn(int qq_num){
	return qq_num % QQ_HASH_SIZE;
}

qq号的链表组织在两个数据结构中,一个双链表当队列使用,保存5min进来的60万个qq号,并且记录加进来的时间戳,定时每秒从队列中删除存活时间大于5min的节点。同时将其组织在一个哈希表上,哈希表用溢出双链表实现,用于快速查找qq号是否在队列里面,也就是是否在5min内登录过的,没有登录则将其加入队列和哈希表。struct
hash_head就是哈希表的头,哈希函数就随便写了一个,常用的求余就可以了。这样既可以保证队列里面的qq最新,也可以快速查找。

代码没时间测试了,只是写出了思路,应该会有细节有错的,业余写算法的随便实现了几个,累的一B,睡觉了

抱歉!评论已关闭.