【剑指Offer】俯视50题之21 - 30题

面试题21 包括min函数的栈  
面试题22 栈的压入、弹出序列  
面试题23 从上往下打印二叉树  
面试题24 二叉搜索树的后序遍历序列  
面试题25 二叉树中和为某一值的路径  
面试题26 复杂链表的复制  
面试题27 二叉搜索树与双向链表  
面试题28 字符串的排列  
面试题29 数组中出现次数超过一半的数字  

面试题30最小的K个数 

/****************************************************/

面试题21 包括min函数的栈 :定义栈的数据结构,请在该类型中实现一个可以得到栈的最小元素的min函数。在该栈中。调用min、push及pop的时间复杂度都是O(1)

思       路:申请一个与原来栈stack大小同样的栈tmpStack。用来保存当前栈中最小元素。stack压入一个元素,tmpStack也压入一个元素,该元素与tmpStack.top比較,大则压入top 否则压入该元素。

出栈同一时候出栈。

实现例如以下:

template <typename> T;
class Stack
{
public:
	Stack();
	~Stack();
	void pop();
	void push(T &value);
	T min();
private:
	stack<T> m_stack;
	stack<T> m_min;
};
void pop()
{
	if (m_min.size() <= 0 || m_stack.size() <= 0)
	{
		return;
	}
	m_stack.pop();
	m_min.pop();
}
void push(T &value)
{
	
	if ( m_min.size() == 0 || value < m_min.top())
	{
		m_min.push(value);
		
	}
	else
	{
		m_min.push(m_min.top());
	}

    m_stack.push(value);

}
T min()
{
	if (m_min.size() > 0)
	{
		return m_min.top();
	}
}



面试题22 栈的压入、弹出序列 :输入两个序列。第一个是栈的压入顺序,请推断第二个1、2、3、4、5、6则4、5、3、2、1是出栈顺序。而4、3、5、1、2就不可能是该压栈序列。

思路:

实现例如以下:

bool IsPopOrder(const int *pPush, const int *pPop, int length)
{
	const int *pPushNext = pPush;
	const int *pPopNext = pPop;
	bool result = false;
	
	if (pPush == NULL || pPop == NULL || length <= 0)
	{
		return false;
	}

	stack<const int> iStack;

	while(pPopNext - pPop < length)/* 弹出序列还没有到头*/
	{
		while(iStack.top() != *pPopNext)
		{
			if (pPushNext - pPush == length)
			{
				break;
			}
			
			iStack.push(*pPushNext);
			pPushNext++;
		}

		if (iStack.top() != *pPopNext)
		{
			break;
		}

		iStack.pop();
		pPopNext++;
	}

	if (iStack.empty() && pPopNext - pPop == length)
	{
		return true;
	}

	return false;
}

面试题23 从上往下打印二叉树 。二叉树的层序遍历

实现例如以下:

struct BinaryTreeNode
{
	int data;
	BinaryTreeNode *lchild;
	BinaryTreeNode *rchild;
};
void LevelOrder(BinaryTreeNode *root)
{
	BinaryTreeNode *pNode;
	if (root == NULL)
	{
		return;
	}
	queue<BinaryTreeNode> iQueue;
	iQueue.push(root);
	while(!iQueue.empty())
	{
		pNode = iQueue.front();
		if (pNode->lchild != NULL)
		{
			iQueue.push(pNode->lchild);
		}
		if (pNode->rchild != NULL)
		{
			iQueue.push(pNode->rchild);
		}
		
		printf("%d",pNode->data);
		iQueue.pop();
	}
}

面试题24 二叉搜索树的后序遍历序列 ,给出一个数组,推断是否是二叉搜索树的后序遍历序列

思路:最后一个结点的值大于左子树的随意值。小于右子树的随意值

实现例如以下:

int  IsSerchTree(int *squeue, int length)
{
	int i,j;
	
	if (squeue == NULL || length <= NULL)
	{
		return false;
	}

	for (i = 0; i < length; i++)
	{
		if (squeue[i] > squeue[length-1])
		{
			break;
		}
	}

	for (j = i, j <length; j++)
	{
		if (squeue[j] < squeue[length -1])
		{
			return false;
		}
	}
	
    if ((true == IsSerchTree(squeue, i)
    	&& (true == IsSerchTree(squeue + i,length - i - 1)))

    {
    	return true;
    }
	
}

面试题25 二叉树中和为某一值的路径 

注意:vector 与 stack和queue的差别

            vector能够从头部删除节点,也能够从尾部遍历整个结构


实现例如以下:

struct BinaryTreeNode
{
	int data;
	BinaryTreeNode *lchild;
	BinaryTreeNode *rchild;
};
void  SumPathTree(BinaryTreeNode *root, int expectSum, vector<int> &iPath, int currentSum)
{
	if (root == NULL)
	{
		return;
	}

	/* 採用前序遍历的方式,先处理根节点 */
	currentSum += root->data;
	iPatch.push_back(root->data);
	
	if ((currentSum == expectSum)
		&& (root->lchild == NULL && root->rchild == NULL)
	{
		for (iterator iter = iPath.begin(); iter < iPath.end(); iter++)
		{
			printf("%d", *iter);
		}
		printf("\n");
	}

	if (root->lchild != NULL)
	{
		SumPathTree(root->lchild,expectSum,iPath,currentSum);
	}

	if (root->rchild != NULL)
	{
		SumPathTree(root->rchild,expectSum,iPath,currentSum);
	}

	/* 假设以上路径都没有期望的值。则回溯到调用之前的结点 递归结束之后,一定回到根结点 */
	iPath.pop_back();
	currentSum-=root->data;
	
}

面试题26 复杂链表的复制 

struct ComplexListNode
{
int data;
ComplexListNode *next;
ComplexListNode *sibling;/* 指向不论什么一个结点 */
};

第一步:每一个节点后面赋值一个同样的结点

第二步:遍历偶数结点。将新结点中sibling指针指向该指的结点

第三步:将链表按奇数偶数。拆分成两个链表。


面试题27 二叉搜索树与双向链表 ,输入一个二叉搜索树,将一个二叉搜索树变成一个排序的双向链表

思路:採用中序遍历二叉树的方式,每次递归记录下来上次遍历到的结点,作为指针传入下次递归

实现例如以下:

struct BinaryTreeNode
{
	int data;
	BinaryTreeNode *lchild;
	BinaryTreeNode *rchild;
};
void ConvertTree(BinaryTreeNode *root, BinaryTreeNode **lastNode)
{
	if (root == NULL)
	{
		return;
	}

	ConvertTree(root->lchild,lastNode);

	root->lchild = lastNode;
	if (*lastNode != NULL)
	{
		(*lastNode)->rchild = root;
	}
	(*lastNode) = root;
	
	ConvertTree(root->rchild,lastNode);
}

BinaryTreeNode *GetHeadNode(BinaryTreeNode *root)
{
	BinaryTreeNode *head;
	if (root == NULL)
	{
		return NULL;
	}
	
	head = root;
	while (head->lchild)
	{
		head = head->lchild;
	}
	return head;
}

面试题28 字符串的排列 

比如:比如输入abc 输出abc的六种排列组合 abc  bac ……

实现例如以下:

#include <iostream>

void printOrderStr(char *str, int length, int index)
{
	
	char temp;
	
	if (str == NULL || length == 0)
	{
		return;
	}
	
	if (index == length)
	{
		for (int i = 0; i<length; i++)
			printf("%c",str[i]);
		printf("\n"); 
	}
	
	for (int i = index; i < length; i++)
	{
		temp = str[index];
		str[index] = str[i];
		str[i] = temp;
		
		printOrderStr(str, length, index+1);
		
		temp = str[index];
		str[index] = str[i];
		str[i] = temp;
		
	} 
}
int main()
{
	char str[] = {'a', 'b', 'c'};
	
	printOrderStr(str, 3, 0);
	
}

扩展题,输入一个字符串输出字符串的各种组合,比如:输入abc 输出a、b、c、ab……abc

实现例如以下:

#include<iostream>
#include<vector>
#include<cstring>
using namespace std;
#include<assert.h>

void Combination_m(char *string ,int number , vector<char> &result)
{
	assert(string != NULL);
	if(number == 0)
	{
		static int num = 1;
		printf("第%d个组合\t",num++);

		vector<char>::iterator iter = result.begin();
		for( ; iter != result.end() ; ++iter)
			printf("%c",*iter);
		printf("\n");
		return ;
	}
	if(*string == '\0')
		return ;

	result.push_back(*string);
	Combination_m(string + 1 , number - 1 , result);
	result.pop_back();
	Combination_m(string + 1 , number , result);
}


void Combination(char *string)
{
	assert(string != NULL);
	
	int i , length = strlen(string);
	for(i = 1 ; i <= 3 ; ++i)
	{
		vector<char> result;
		Combination_m(string , i ,result);
	}
}


int main(void)
{
	char str[] = "abc";
	Combination(str);
	getchar();
	return 0;
}



面试题29 数组中出现次数超过一半的数字 。给定一个数组,当中有一个数组其个数超过一半。求该数

思路:

最简单的就是排序,求中位数。

採用一个数记录反复个数,一个数记录结果,详细实现例如以下:

int FindMoreThanHalf(int num[], int length)
{
	int times = 0;
	int result;
	if (num == NULL || length <=0 )
	{
		return 0;/* 非法输入*/
	}

	result = num[0];
	times++;
	for (int i = 1; i < length; i++)
	{
		
		if (num[i] == result)
		{
			times++;
		}

		if (times == 0)
		{
			result = num[i];
		}

		if (num[i] != result && times > 0 )
		{
			times--;
		}
	}

	return times;
}


面试题30 最小的K个数 

#include <stdlib.h>
#include <stdio.h>
/* 求最小的K个数 */

int partition(int *psArray, int num, int startIndex, int endIndex)
{
	int iTemp;
	int i = startIndex;
	int j = endIndex;
	
	if (psArray == NULL || num <= 0 || startIndex > endIndex || startIndex < 0 || endIndex < 0)
	{
		return 0;
	}

	iTemp = psArray[0];
	
	while (i < j)
	{
		while ((i < j) && (psArray[i] <= psArray[j]))
			j--;
			
		if (i < j)
		{
			iTemp = psArray[i];
			psArray[i] = psArray[j];
			psArray[j] = iTemp;			
		}

		while((i < j) && (psArray[i] <= psArray[j]))
			i++;
		
		if (i < j)
		{
			iTemp = psArray[i];
			psArray[i] = psArray[j];
			psArray[j] = iTemp;			
		}
	}
	return i;	
}
void FindMinKNum(int *psArray, int num, int k)
{
	int i;
	int j;
	if (k > num)
	{
		return;
	}

	i = partition(psArray,num,0,num-1);
	while (i != k-1)
	{
		if (i < k-1)
		{
			i = partition(psArray,num,i+1,num-1);
		}
		else
		{
			i = partition(psArray,num,0,i-1);
		}
	}
	for (j = 0; j <= i; j++)
	{
		printf(" %d", psArray[j]);
	}
	printf("\n");
	
}
int main()
{
	int a[]={3,4,5,1,2};
	FindMinKNum(a, 5, 2);
	
}

能够用O(n*logk)的时间复杂度加上O(k)的空间复杂度来实现。

void GetLeastNumbers(int *psArray, int length, int k)
{
	if (psArray == NULL || length < 0 || k < 0 || length < k)
	{
		return;
	}

	multiset<int, greater<int> > iMultiset;
	multiset<int, greater<int> >::iterator iSetIterator;

	for (int i = 0; i < length; i++)
	{
		if (i < k)
		{
			iMultiset.insert(psArray[i]);
		}
		else
		{
			if (psArray[i] < *(iMultiset.begin()))
			{
				iMultiset.erase(iMultiset.begin());
				iMultiset.insert(psArray[i]);
			}
		}
	}
	for (iSetIterator = iMultiset.begin();  iSetIterator != iMultiset.end(); iSetIterator++ )
	{
		printf(" %d", *iSetIterator);
	}
	printf("\n");
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值