精选微软等公司数据结构+算法面试100题带答案(1-10)

1、输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表。要求不能创建任何新的结点,只调整指针的指向。
10
/ \
6 14
/ \ / \

4 8 12 16

转换成双向链表:4=6=8=10=12=14=16。

#include <stdlib.h>
#include "stdafx.h"

//数据结构
struct BSTreeNode
{
	int m_nValue; 
    BSTreeNode *m_pLeft; 
    BSTreeNode *m_pRight; 
};

//root根节点,返回head、tail分别为双向链表的头尾节点
void helper(BSTreeNode *& head, BSTreeNode *& tail, BSTreeNode *root) {
	BSTreeNode *lt, *rh;

	//递归终止函数
	if (root == NULL) 
	{
		head = NULL, tail = NULL;
		return;
	}

	//递归调用
	helper(head, lt, root->m_pLeft);
	helper(rh, tail, root->m_pRight);
	
	//左节点和根节点调整关系
	if (lt!=NULL) 
	{
		lt->m_pRight = root;
		root->m_pLeft = lt;
	} 
	else 
	{
		head = root;
	}

	//右节点和根节点调整关系
	if (rh!=NULL) 
	{
		root->m_pRight=rh;
		rh->m_pLeft = root;
	} 
	else 
	{
		tail = root;
	}
}

//二叉搜索树转换成双向链表
BSTreeNode * treeToLinkedList(BSTreeNode * root) 
{
	BSTreeNode * head, * tail;
	helper(head, tail, root);
	return head;
}

void main()
{

}

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

#include "stdafx.h"
#include "stdlib.h"
#include "string.h"
#include "iostream.h"


//数据结构
typedef struct Stack
{
	int data;
	struct Stack *next;
}*pStack;

typedef struct MinStack {  //外层结构体封装数据和最小值
	pStack stack;   //内层结构体存放数据
	int min;
	int size;
}*pMinStack;

//初始化
void MinStackInit(pMinStack &mStack,int size)
{
	mStack=new MinStack;
	mStack->stack=NULL;
	mStack->size=size;
	mStack->min=0;
}

//释放栈的内存空间
void MinStackFree(pMinStack &mStack) 
{
	pStack temp=mStack->stack;
	while(mStack->stack!=NULL)
	{
		temp=mStack->stack;
		mStack->stack=mStack->stack->next;
		delete temp;
		temp=NULL;
	}

	delete mStack;
}

//栈长度
int LenStack(MinStack mStack) //不能用指针传参
{
	int len=0;
	while(mStack.stack!=NULL)
	{
		mStack.stack=mStack.stack->next;
		len++;
	}

	return len;
}

//push操作
void MinStackPush(pMinStack mStack, int d) 
{
	int len=LenStack(*mStack);
	pStack s=mStack->stack;
	if (len>=mStack->size)
	{
		cout<<"statck is full!"<<endl;
		return;
	}
	if (s==NULL)  //第一次push数据
	{
		s=new Stack;
        s->data=d;
    	s->next=NULL;
		mStack->stack=s;
		mStack->min=d;
	}
	else
	{
	    pStack temp=new Stack;
		temp->data=d;
		temp->next=mStack->stack;
		mStack->stack=temp;
		mStack->min=mStack->min>d?d:mStack->min;
	}
}

//pop操作
int MinStackPop(pMinStack mStack) 
{
	if (mStack==NULL||mStack->stack==NULL) 
	{
		cout<<"stack is empty!"<<endl;
		exit(1);
	}
	
	int data=mStack->stack->data;
	pStack temp=mStack->stack;
	mStack->stack=mStack->stack->next;
	delete temp;
	temp=NULL;

	return data;
}

//min操作
int MinStackMin(pMinStack mStack) 
{
	if (mStack==NULL||mStack->stack==NULL) 
	{
		cout<<"stack is empty!"<<endl;
		exit(1);
	}

	return mStack->min;
}

void main()
{
	pMinStack pStack=NULL;  
	MinStackInit(pStack,10);

	for (int i=10;i<21;i++)
	{
		MinStackPush(pStack,i);
	}

	cout<<"stack min:"<<MinStackMin(pStack)<<endl;

	for (i=10;i<21;i++)
	{
		cout<<MinStackPop(pStack)<<endl;
	}

	MinStackFree(pStack);
}

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

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

    见:http://blog.csdn.net/dazhong159/article/details/7792722

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

    见:http://blog.csdn.net/dazhong159/article/details/7906916

5、输入n个整数,输出其中最小的k个。
例如输入1,2,3,4,5,6,7和8这8个数字,则最小的4个数字为1,2,3和4。

    思路:1)维护一个由k个元素(n个元素前k个元素初始化)组成的最大根堆

               2)将剩余元素与根节点比较,如果根节点较大,则交换两者的值

               3)重新将堆更新为最大根堆,继续第二步,直到遍历完所有的n个整数,最后这个堆中的元素就是最小的k个元素。

6、给你10分钟时间,根据上排给出十个数,在其下排填出对应的十个数,要求下排每个数都是先前上排那十个数在下排出现的次数。(智力题?)

上排的十个数如下: 【0,1,2,3,4,5,6,7,8,9】
举一个例子:
数值: 0,1,2,3,4,5,6,7,8,9
分配: 6,2,1,0,0,0,1,0,0,0
以此类推..

7、给出俩个单向链表的头指针,比如h1,h2,判断这俩个链表是否相交。为了简化问题,我们假设俩个链表均不带环。
    “如果两个没有环的链表相交于某一节点,那么在这个节点之后的所有节点都是两个链表共有的”这个特点,我们可以知道,如果它们相交,则最后一个节点一定是共有的。而我们很容易能得到链表的最后一个节点。那么,我们只要判断俩个链表的尾指针是否相等。相等,则链表相交;否则,链表不相交。

问题扩展:
1.如果链表可能有环列?

struct Node  
{  
    int value;  
    Node * next;  
};  

//1.先判断带不带环  
//判断是否有环,返回bool,如果有环,返回环里的节点  
//思路:用两个指针,一个指针步长为1,一个指针步长为2,判断链表是否有环  
bool isCircle(Node * head, Node *& circleNode, Node *& lastNode)  
{  
    Node * fast = head->next;  
    Node * slow = head;  
    while(fast != slow && fast && slow)  
    {  
        if(fast->next != NULL)  
            fast = fast->next;  
		
        if(fast->next == NULL)  
            lastNode = fast;  
        if(slow->next == NULL)  
            lastNode = slow;  
		
        fast = fast->next;  
        slow = slow->next;  	
    }  
    if(fast == slow && fast && slow)  
    {  
        circleNode = fast;  
        return true;  
    }  
    else  
        return false;  
}  

//判断带环不带环时链表是否相交  
//2.如果都不带环,就判断尾节点是否相等  
//3.如果都带环,判断一链表上俩指针相遇的那个节点,在不在另一条链表上。  
bool detect(Node * head1, Node * head2)  
{  
    Node * circleNode1;  
    Node * circleNode2;  
    Node * lastNode1;  
    Node * lastNode2;  
	
    bool isCircle1 = isCircle(head1,circleNode1, lastNode1);  
    bool isCircle2 = isCircle(head2,circleNode2, lastNode2);  
	
    //一个有环,一个无环  
    if(isCircle1 != isCircle2)  
        return false;  
    //两个都无环,判断最后一个节点是否相等  
    else if(!isCircle1 && !isCircle2)  
    {  
        return lastNode1 == lastNode2;  
    }  
    //两个都有环,判断环里的节点是否能到达另一个链表环里的节点  
    else  
    {  
        Node * temp = circleNode1->next;  //updated,多谢苍狼 and hyy。  
        while(temp != circleNode1)    
        {  
            if(temp == circleNode2)  
                return true;  
            temp = temp->next;  
        }  
        return false;  
    }  
	
    return false;  
} 

2.如果需要求出俩个链表相交的第一个节点列?

unsigned int ListLength(Node* pHead)  
{  
	unsigned int nLength = 0;  
	Node* pNode = pHead;  
	while(pNode != NULL)  
	{  
		++ nLength;  
		pNode = pNode->next;  
	}  
    return nLength;  
}

Node* FindFirstCommonNode( Node *pHead1, Node *pHead2)  
{  
     // Get the length of two lists  
    unsigned int nLength1 = ListLength(pHead1);  
    unsigned int nLength2 = ListLength(pHead2);  
	int nLengthDif = nLength1 - nLength2;    
	
	// Get the longer list  
	Node *pListHeadLong = pHead1;  
	Node *pListHeadShort = pHead2;  
	if(nLength2 > nLength1)  
	{  
		pListHeadLong = pHead2;  
		pListHeadShort = pHead1;  
		nLengthDif = nLength2 - nLength1;  
	}  
  
	// Move on the longer list  
	for(int i = 0; i < nLengthDif; ++ i)  
		pListHeadLong = pListHeadLong->next;  
	// Move on both lists  
	while((pListHeadLong != NULL) && (pListHeadShort != NULL) && (pListHeadLong != pListHeadShort))  
	{  
		pListHeadLong = pListHeadLong->next;  
		pListHeadShort = pListHeadShort->next;  
	}  
	
    // Get the first common node in two lists  
	Node *pFisrtCommonNode = NULL;  
	if(pListHeadLong == pListHeadShort)  
		pFisrtCommonNode = pListHeadLong;  
	return pFisrtCommonNode;  
}  

8、(1)你让一些人为你工作了七天,你要用一根金条作为报酬。金条被分成七小块,每天给出一块。如果你只能将金条切割两次,你怎样分给这些工人?

    切割两次,分成1、2、4三段。第一条给1块,第二天给2块,找回一块,第三天给找回的那一块,第四天给4块,找回之前的一和二块...以此类推。

      (2)假设你有一个用1001 个整数组成的数组,这些整数是任意排列的,但是你知道所有的整数都在1 到1000(包括1000)之间。此外,除一个数字出现两次外,其他所有数字只出现一次。假设你只能对这个数组做一次处理,用一种算法找出重复的那个数字。如果你在运算中使用了辅助的存储方式,那么你能找到不用这种方式的算法吗?

    使用异或,因为:A XOR A XOR B = B:

int findX(int a[]) 
{
	int k = a[0];
	for (int i=1; i<=1000;i++)
		k ^= a[i]^i;
	return k;
}

9、输入一个整数数组,判断该数组是不是某二元查找树的后序遍历的结果。如果是返回true,否则返回false。
例如输入5、7、6、9、11、10、8,由于这一整数序列是如下树的后序遍历结果:
     8
     / \
    6 10
   / \   / \
  5 7 9 11
因此返回true。如果输入7、4、6、5,没有哪棵树的后序遍历的结果是这个序列,因此返回false。

    思路:二叉查找树的后序遍历的一个不变的法则就是Root节点永远是在输出序列的最后一个,这里也就是在整数数组的最后一个元素就是Root节点,然后从数组的开始找到大于Root节点的值,把该值左边的当作左子树,把该值及它右边的当做右子树,因为根据二元查找树的规则,左子树的节点一点小于Root节点,右子树中的所有节点一定大于Root节点,所以我们按照这个规则不断的递归调用并进行判断,直到结束。
其实题目的关键点是确定左子树和右子树的Position。

#include "stdafx.h"
#include "stdlib.h"
#include "string.h"
#include "iostream.h"

// 根据二叉查找树的特点----左子树都比右子树小,比根节点大
// 找出左右子树,递归处理并判断。
bool IsSquenceBSTree(const int *pA, int nLen)
{
	if(NULL == pA || nLen <= 0)
		return false;
	
	// 根节点
	int nRoot = pA[nLen - 1];
	
	// 左右子树的分水岭
	int i = 0;
	for(; i < nLen - 1; ++ i)
	{
		if(pA[i] > nRoot)
			break;
	}
	
	// 出现右子树比根节点小的情况,则不满足条件(也可以用左子树进行判断)
	int j = i;
	for(; j < nLen - 1; ++j)
	{
		if(pA[j] < nRoot)
			return false;
	}
	
	// 递归处理左子树
	bool bLeft = true;
	if(i > 0)
		bLeft = IsSquenceBSTree(pA, i);
	
	// 递归处理右子树
	bool bRight = true;
	if(i < nLen - 1)
		bRight = IsSquenceBSTree(pA + i, nLen - i - 1);
	
	return (bLeft && bRight);
}


int main(int argc, char* argv[])
{
	int aryA[] = {7,4, 6, 5,};
	
	if (IsSquenceBSTree(aryA, sizeof(aryA)/sizeof(int)))
	{
		cout << "Yes" << endl;
	}
	else
	{
		cout << "No" << endl;
	}
	
	return 0;
}

10、输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变。句子中单词以空格符隔开。为简单起见,标点符号和普通字母一样处理。例如输入“I am a student.”,则输出“student. a am I”。

    思路:先将整个字符串反转,然后在将字符串中的每个单词反转即可。

#include "stdafx.h"
#include "stdlib.h"
#include "string.h"
#include "iostream.h"

//反转字符串中的某段
void ResWord(char *s,int start,int end)
{
	char temp;
	for (int i=0;i<(end-start)/2;i++)
	{
		temp=*(s+start+i);
		*(s+start+i)=*(s+end-1-i);
		*(s+end-1-i)=temp;
	}
}

//现将字符串反转,然后再将字符串中的每个单词反转
void ResString(char *s)
{
	ResWord(s,0,strlen(s));  

	int iStart=0,iEnd=-1;  //标志单词的起始和结束位置(0~n)
	char *p=s;
	while(*p!='\0')
	{
		iEnd++;
		if (*p==' '||*(p+1)=='\0') 
		{
			if(*(p+1)=='\0') //最后一个单词,由于没有访问到'\0'(' '),手动iEnd++
				iEnd++;
			ResWord(s,iStart,iEnd);  
			iStart=iEnd+1;
		}
		p++;
	}
}

void main()
{
	char a[]="you! love I";
	ResString(a);
	cout<<a<<endl;
}

 

文章转载于:http://blog.csdn.net/v_JULY_v/article/details/5968678

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值