看了JULY博客的微软100题,个人觉得全部完成一次对以后找工作还是非常有帮助的
PS:所有题目来源均来自July
1.把二元查找树转变成排序的双向链表
这题太简单了,先序遍历一变树然后做一个链表即可,比起遍历的算法,二叉查找树的建立更有难度
typedef struct tagNode
{
tagNode *lChild;
tagNode *rChild;
int v;
}Node;
Node *addBSTreeNode(std::vector<int> &vect,int i,int j)
{
if(i>j)
return NULL;
Node *p = new Node;
p->v = vect[(i+j)/2];
p->lChild = addBSTreeNode(vect,i,(i+j)/2-1);
p->rChild = addBSTreeNode(vect,(i+j)/2+1,j);
return p;
}
输入的参数是一个已经排好序的int型vector容器,i和j代表起始和终点
2.设计包含min函数的栈。
定义栈的数据结构,要求添加一个min函数,能够得到栈的最小元素。
要求函数min、push以及pop的时间复杂度都是O(1)。
我采用的方法是索引,压入一个元素的时候,实际压入的是一个结构体,里面包含了该元素的最小值的索引。
如果新压入一个元素的大小比当前栈顶元素的索引所指向的元素小的话,那么新压入的元素的索引就指向它自己,否则新元素的索引与上一个元素的索引一致。
template <class _Ty>
class Q2_stack{
typedef _Ty valueType;
struct Q2_struct{
valueType value;
unsigned int index;
};
public:
Q2_stack(){
stack_grow = 256;
pos = -1;
stack = new Q2_struct[stack_grow];
}
Q2_stack(int grow){
stack_grow = grow;
pos = -1;
stack = new Q2_struct[stack_grow];
}
~Q2_stack(){
delete []stack;
}
void push(const valueType &value);
void pop(void);
const valueType &min(void);
protected:
Q2_struct *stack;
int stack_grow;//栈容量增长因子
int pos;//指向栈顶元素的位置
};
template <class _Ty>
void Q2_stack<_Ty>::push(const valueType &value)
{
int stack_size = pos + 1;
if( stack_size != 0 && stack_size % stack_grow == 0)//超出当前栈容量,则栈容量翻一倍
{
Q2_struct *new_stack = new Q2_struct[stack_size*2];
memcpy(new_stack,stack,sizeof(Q2_struct)*stack_size);
delete []stack;
stack = new_stack;
}
Q2_struct new_element;
new_element.value = value;
if(stack_size != 0)
{
if(value < stack[stack[pos].index].value)
new_element.index = pos+1;
else
new_element.index = stack[pos].index;
}
else{
new_element.index = 0;
}
stack[++pos] = new_element;
}
template <class _Ty>
void Q2_stack<_Ty>::pop(void)
{
if(pos == -1)
return;
pos--;
}
template <class _Ty>
const _Ty & Q2_stack<_Ty>::min(void)
{
return stack[stack[pos].index].value;
}
3.求子数组的最大和
题目:
输入一个整形数组,数组里有正数也有负数。
数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和。
求所有子数组的和的最大值。要求时间复杂度为O(n)。
July的解答已经很不错了,个人是想不出更好的方法了,这是他的代码
int MaxSection(int *a,int len)
{
int b = 0, result = 0;
for(int i = 0; i < len; i++)
{
if(b <= 0)//如果当前组合已经小于0了,那么就抛弃掉,从新的起点开始
b = a[i];
else
b += a[i];//计算当前组合的和
if(result < b)//比对当前组合的和与上一次组合的和的大小,取大的
result = b;
}
return result;
}
可以提点的是,如果题目条件更改一下的话,如:数组可能不存在正数,那么答案要修正的地方就是result的初值从0改为a[0]
4.在二元树中找出和为某一值的所有路径
题目:输入一个整数和一棵二元树。
从树的根结点开始往下访问一直到叶结点所经过的所有结点形成一条路径。
打印出和与输入整数相等的所有路径。
例如 输入整数22和如下二元树
10
/ \
5 12
/ \
4 7
则打印出两条路径:10, 12和10, 5, 7。
这道题就是一道求指定带权路径的问题,首先我们可以先思考如何找到单条这样的路径
struct tagNode
{
tagNode *lChild;
tagNode *rChild;
int v;
};
typedef tagNode Node;
using namespace std;
/*找到一条符合条件的路径的算法*/
void FindSingleWay(Node *root,int expected,int &cur)
{
cur += root->v;
//如果当前路径已经大于我们要的值,那么就没必要遍历下去了
if(cur < expected)
{
if(root->lChild)
FindSingleWay(root->lChild,expected,cur);
if(root->rChild)
FindSingleWay(root->rChild,expected,cur);
}
//走到这里有几种可能,路径已经找到,走到了叶子结点,或者是当前cur值已经超出了我们需要的值
if(cur == expected)
{
cout << root->v << " ";
}
else //由于此路径已经无效,因此进行回溯
cur -= root->v;
}
要找到所有的路径,我们需要一个额外的栈来保存我们遍历的路径,这里采用vector来做为栈存储结构,为了方便的遍历栈中元素的,所以不采用stack容器
/*找到所有符合条件的路径的算法*/
void FindAllWay(std::vector<int> &s,Node *root,int expected,int &cur)
{
cur += root->v;
//把当前路径加入到栈中
s.push_back(root->v);
//如果当前路径已经大于我们要的值,那么就没必要遍历下去了
if(cur < expected)
{
if(root->lChild)
FindAllWay(s,root->lChild,expected,cur);
if(root->rChild)
FindAllWay(s,root->rChild,expected,cur);
}
//走到这里有几种可能,路径已经找到,走到了叶子结点,或者是当前cur值已经超出了我们需要的值
if(cur == expected)
{
//此时栈中肯定只有一条符合条件的路径,原因见if外的语句
//从栈底向栈顶进行遍历
for(std::vector<int>::iterator it = s.begin(); it != s.end(); it++)
cout << *it << " ";
cout << endl;
}
//这里和单条路径不一样,无论是否找到都要进行回溯的处理,栈中始终保持着当前所走的路径
//回到上一个结点,并删除栈顶当前的结点
cur -= root->v;
s.pop_back();
}