July的微软面试100题系列尝试解答(1~5题)



1.把二元查找树转变成排序的双向链表(树)
 题目:
输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表。
要求不能创建任何新的结点,只调整指针的指向。
   10
  / \
  6  14
 / \ / \
4  8 12 16
 转换成双向链表
4=6=8=10=12=14=16。
 
 首先我们定义的二元查找树 节点的数据结构如下:
 struct BSTreeNode
{
  int m_nValue; // value of node
  BSTreeNode *m_pLeft; // left child of node
  BSTreeNode *m_pRight; // right child of node
};

我看到这题的时候首先想到的是中序遍历该BST树,这样顺序与双向链表就一样了。假定m_pLeft指向前驱,m_pRight指向后继,需要在大脑中不断的浮现BST树和双向链表的结构,需要对这两种结构很熟悉.为了实现遍历BST树,我用了栈,结构定义省略。


void BST2DulLinkList(BSTree&T, BSTree&L){//参数L在函数结束后作为双向链表的首节点存在
	Stack S;
	InitStack(S);
	BSTree p = NULL;
	int flag = 0;//标志位
	while (T || S.top != S.base){
		if (T){
			Push(S, T);//跟指针进栈
			T = T->m_pLeft;//指向左子树
		}
		else{
			Pop(S, T);
			if (flag == 0){//flag=0表示为最左下的结点为首节点
				L = T;//L指向双向链表的第一个结点,以后保持不动了
				p = T;//p总是指向最后一个节点
				flag = 1;
			}
			else{
				p->m_pRight = T;//每次Pop后,T为最新的结点,接在p的后面
				T->m_pLeft = p;//T的前驱为p
				p = p->m_pRight;//p向后移动
			}
			T = T->m_pRight;//指向右子树
		}
	}
	//上面循环结束后p指向最后一个结点
	L->m_pLeft = p;//首节点的前驱指向最后一个节点
	p->m_pRight = L;//最后一个结点的后继指向首节点
}

2.设计包含min函数的栈(栈)
定义栈的数据结构,要求添加一个min函数,能够得到栈的最小元素。
要求函数min、push以及pop的时间复杂度都是O(1)。

我觉得关键是在Push的时候顺带比较已经在栈中的元素,且每次要入栈的元素总与栈顶元素比较,小的放在栈顶,在全部元素Push之后,栈顶元素为最小的一个。且每次Push时时间复杂度为O(1)

void SuperPush(Stack1&S, int data){
	if (S.top - S.top == S.stacksize){
		if ((S.base = (int*)realloc(S.base, sizeof(int)*(STACK_SIZE + STACK_INCREMENT))) == NULL){
			printf("分配节点失败\n");
			exit(EXIT_FAILURE);
		}
		S.top = S.base + S.stacksize;
		S.stacksize += STACK_INCREMENT;
	}
	if (S.top != S.base){//栈中有数据
		if (data > *(S.top - 1)){//和栈顶元素比较,准备做交换
			int t = data;
			data = *(S.top - 1);
			*(S.top - 1) = t;
		}
		*S.top++ = data;//此时data为小元素,入栈
	}
	else{
		*S.top++ = data;//第一次入栈,只执行一次
	}
}


3.求子数组的最大和(数组)
题目:
输入一个整形数组,数组里有正数也有负数。
数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和。
求所有子数组的和的最大值。要求时间复杂度为O(n)。

例如输入的数组为1, -2, 3, 10, -4, 7, 2, -5,和最大的子数组为3, 10, -4, 7, 2,
因此输出为该子数组的和18。


上接上代码比较能看得懂吧:

int maxSubarray(int a[], int size) {
	int max = INT_MIN;
	int sum = 0;
	for (int i = 0; i < size; i++){
		sum += a[i];
		if (sum>max){
			max = sum;
		}
		else if (sum < 0){
			sum = 0;
		}
	}
	return max;
}

在二元树中找出和为某一值的所有路径(树)

题目:输入一个整数和一棵二元树。
从树的根结点开始往下访问一直到叶结点所经过的所有结点形成一条路径。
打印出和与输入整数相等的所有路径。
例如 输入整数22和如下二元树
    10 
  /   /  
 5    12  
/ \     
4  7
则打印出两条路径:10, 12和10, 5, 7。

二元树节点的数据结构定义为:
struct BinaryTreeNode // a node in the binary tree
{
int m_nValue; // value of node
BinaryTreeNode *m_pLeft; // left child of node
BinaryTreeNode *m_pRight; // right child of node
};


需要用到递归的实现,路径用一个数组保存,曾次数用作路径的下标。用输入的整数减去每一次递归的层次树的结点值,知道捡到0为止并左右子树都为空时,就算找到了一条路径


void Local(BSTree root, int sum, int path[], int top) {
	path[top++] = root->m_nValue;//根节点为一条路径
	sum -= root->m_nValue;//num减去根节点值,为下一次递归做新的num
	if (root->m_pLeft == NULL&&root->m_pRight == NULL){//如果左右子树为空,且sum为0,则找到了路径,打印数组保存到额路径
		if (sum == 0){
			printPath(path, top);
		}
	}
	else{
		if (root->m_pLeft != NULL){//没有到叶子节点,继续递归遍历
			Local(root->m_pLeft, sum, path, top);//把当前的参数传给下一个函数调用栈
		}
		if (root->m_pRight != NULL){
			Local(root->m_pRight, sum, path, top);
		}//两个if分支都要执行一遍
	}
	--top;//一个层次自减,表示该层已经递归完毕,转到回溯到上一层。
	sum += root->m_nValue;//将刚刚减过的数加回来,回到上一层。
}
#define MAX_HEIGHT 3
void printPaths(BSTree  &root, int sum) {

	int path[MAX_HEIGHT];
	Local(root, sum, path, 0);//获得结果路径的函数,需要根节点,和,保存路径的数组,当前符合要求的结点的层数
}


5.查找最小的k个元素(数组)
题目:输入n个整数,输出其中最小的k个。
例如输入1,2,3,4,5,6,7和8这8个数字,则最小的4个数字为1,2,3和4。


我看到此题时,首先想到的是堆。构造一个最小堆,需要三个函数,第一个是维护最小堆性质的函数,第二个是建立最小堆,第三个是模仿了堆排序,将根节点的元素与堆中最后一个元素交换,这样最后一个元素成为了最小元素,打印他然后再次维护最小堆的性质,每次循环总是最小的元素被打印出来,其中min_heap_property,build_min_heap,heap_search_min为核心的函数,其它为辅助函数。以及宏变量。

#define RIGHTCHILD(i) 2*i+1
#define LEFTCCHILD(i) 2*i
#define PARENT(i) i/2
#define MAX_HEAP_SIZE 100
#define HEAP_INCREMENT 2
typedef struct HeapArr{
	int length;
	int heap_size;
	int *arr;
	int*cur;
}HeapArr;
void InitHeapArr(HeapArr&A){
	if ((A.arr = (int*)malloc(sizeof(int)*MAX_HEAP_SIZE) + 1) == NULL){
		printf("空间分配失败\n");
		exit(EXIT_FAILURE);
	}
	A.cur = A.arr;
	A.cur++;
	A.length = MAX_HEAP_SIZE;
	A.heap_size = 0;
}
void AssignHeapArr(HeapArr&A, int data){
	*A.cur++ = data;
	A.heap_size++;
}
void ShowHeapArr(HeapArr&A, int len){
	for (int i = 1; i <= len; i++){
		printf("%d ", A.arr[i]);
	}
}

/*维护最小堆的性质的函数*/
void min_heap_property(HeapArr&A, int i){
	int left = LEFTCCHILD(i);
	int right = RIGHTCHILD(i);
	int largest;
	if (left <= A.heap_size&&A.arr[left] < A.arr[i]){
		largest = left;
	}
	else largest = i;
	if (right <= A.heap_size&&A.arr[right] < A.arr[largest]){
		largest = right;
	}
	if (largest != i){
		int t = A.arr[i];
		A.arr[i] = A.arr[largest];
		A.arr[largest] = t;
		min_heap_property(A, largest);
	}
}
void build_min_heap(HeapArr&A){
	for (int i = A.heap_size / 2; i >= 1; i--){
		min_heap_property(A, i);
	}
}
void heap_search_min(HeapArr&A, int n){
	build_min_heap(A);
	int i, j;
	for (i = A.heap_size, j = 0;/* i >= 2 &&*/ j < n; i--, j++){
		int t = A.arr[1];
		A.arr[1] = A.arr[i];
		A.arr[i] = t;
		printf("%d ", A.arr[A.heap_size]);
		A.heap_size--;
		min_heap_property(A, 1);
	}
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值