剑指offer chapter 4

Q19 求二叉树的镜像

void MirrorRecursively(TreeNode* pNode)
{
	if(!pNode || (!pNode->left && !pNode->right)
		return;
	
	TreeNode* pmid = NULL;
	pmid = pNode->right;
	pNode->right = pNode->left;
	pNode->left = pmid;

	if(pNode->left)
		MirrorRecursively(pNode->left);
	if(pNode->right)
		MirrorRecursively(pNode->right);

}


Q20 顺时针打印矩阵

用递归来解决,从右上角第一个数(index,index)来标识相应的圈;
int main()
{
	void PrintMatrixClockwisely(int **numbers, int col, int row);
	
	int col = 4, row = 5;        // 生成二维数组
	int **a = new int*[col];
	for (int i = 0; i < col;++i)
	{
		a[i] = new int[row];
		for (int j = 0; j < row; ++j )
			a[i][j] = i + j*2;
	}

	for(int i = 0; i< col;++i)   // 打印生成的二维数组
	{
		for(int j = 0; j < row; ++j)
			cout<<a[i][j]<<" ";
		cout<<endl;
	}
	cout<<endl;

	PrintMatrixClockwisely(a,col,row);   // 顺时针打印
}

void PrintMatrixOuter(int **numbers,int col,int row,int index);

void PrintMatrixClockwisely(int **numbers, int col, int row)
{
	if(numbers==NULL || col <= 0|| row <= 0)
		return;
	int index = 0;
	PrintMatrixOuter(numbers,col,row,index);   // 递归依次打印最外一圈的数据
}

void PrintMatrixOuter(int **numbers,int col,int row,int index)
{
	if(col <= 0 || row <= 0)   // 递归退出条件
		return;
	// 最后肯定是只剩下1行n列或是2行m列
	int i, j;
	// 打印最上一行
	for (i  = index,j = index; j <= index+row-1;++j)
		cout<< numbers[i][j]<<" ";

	// 打印最右一列
	if(row >= 1)   // 这里要=1因为如果是只有一列的话可以直接打印
		for(i = index+1,j = index+row-1; i <= index+col-1; ++i)
			cout<< numbers[i][j]<<" ";

	// 打印最下一行
	if(col > 1)
		for(i = index+col-1,j = index+row-2; j >= index; --j)
			cout<< numbers[i][j]<<" ";

	// 打印最左一列
	if(row >1)
		for(i = index+col-2,j = index; i > index; --i)
			cout<< numbers[i][j]<<" ";
	cout<<endl;
	PrintMatrixOuter(numbers,col-2,row-2,++index);
}




Q21 包含min函数的栈

功能是实现:push, pop 时间复杂度0(1),min函数时间复杂度也为0(1)

过程:
用两个栈,一个用于正常的push, pop,另一个辅助栈用于压入与删除当前最小值;
即每次压入一个值时,将最小值也压入,每次删除一个值时,将辅助栈当前的栈顶也删除;

Q22 判断栈的弹出序列

如压栈序列是1 2 3 4 5,则4 5 3 2 1是其一个弹出序列,而 4 5 2 3 1不是其弹出序列;

解决:
1. 弹出栈的当前值为4,而栈顶当前为空值不为4,则将还未入栈的值一直往里面压,直到找到4;
2. 弹出栈的当前值为5, 而栈顶值不为5,继续压入栈,直到找到5;
...

如果所有的数都压入栈还没找到当前值,则说明该序列不是弹出序列;
如果弹出序列的最后一个值也从栈中或是未压入的序列中找到,则说明是弹出序列;

bool IsPopOrder(cinst int* bPush,const int* bPop,const int len) 
	if bPush == NULL || bPop == NULL || len <= 0
		return false;
	int *pPush = bPush, *pPop = bPop;
	bool isPopOrder = false;
	stack<int>stackData;
	while(pPop - bPop < len) // 没有越界
		while(stackData.empty() || stackData.top() != *pPop || pPush < bPush + len)
			stackData.push(*pPush++);
		// 上面循环退出时,栈顶元素与当前值相等的或是已经全部找完
		if(pPush = bPush + len)  // 越界
			break;
		// 否则是栈顶元素与弹出值相等
		stackData.pop();
		++bPop;
	
	if(stackData.empty() && pPop - bPop = len)  // 最后是栈为空,pPop指向出界处
		isPopOrder = true;
	return isPopOrder;


Q24 判断某数组序列是二叉搜索树的后序排列

如: 5 7 6 9 11 10 8; 其中8为根结点,左子树为结点都<8,右子树结点都>8,递归进入左右子树再次判断;
递归结束条件:当前结点为叶子结点;

bool VerifySquenceOfPostBST(int sequen[],int len)
{
	if(sequen==NULL || len < 0)
		return false;
	if(len == 1)
		return true;

	int rootVal = sequen[len-1];
	int pos = 0;
	for (;pos < len;++pos)
		if(sequen[pos] > rootVal)
			break;   // 找到右子树的第一个数
	for (int j = pos; j < len; ++j)
		if(sequen[j] < rootVal)
			return false;  // 如果右子树中有存在比根值小的数则说明非二叉搜索树
	// 这时,根结点的左右两边是满足二叉搜索树条件的
	bool resLeft = true, resRight = true;
	if(pos > 0)
		resLeft = VerifySquenceOfPostBST(sequen,pos);
	if(len - pos -1 > 0)
		resRight = VerifySquenceOfPostBST(sequen,len-pos-1);
	return resLeft&&resRight;
}

Q26 复杂链表的复制

下面的代码还未测试
// 复制结点
void CopyNode(ComplexListNode* pHead)
{
	if(!pHead)
		return;
	ComplexListNode* pNode = pHead;
	while(pNode)
	{
		ComplexListNode *cpyNode = new ComplexListNode;
		cpyNode->val = pNode->val;
		cpyNode->pNext = pNode->pNext;
		cpyNode->pSibling = NULL;
		pNode->pNext = cpyNode;

		pNode = cpyNode->pNext;
	}
}

// 连接另一结点
void CopySibling(ComplexListNode* pHead)
{
	if(!pHead)
		return;
	ComplexListNode* pNode = pHead, *pCpyNode = pHead->pNext;

	while(pNode)   // 在非空原始结点的后面插入它的复制结点
	{ 
		pCpyNode->pSibling = pNode->pSibling->pNext;
		pNode = pCpyNode->pNext;
		pCpyNode = pCpyNode->pNext->pNext;
	}
}

// 分离链表
ComplexListNode* DivList(ComplexListNode* pHead)
{
	if(!pHead)
		return NULL;

	ComplexListNode* cpyHead = pHead->pNext, *pNode = pHead;   // 复制链表的新头结点
	ComplexListNode* pClone = cpyHead;

	while(pClone->pNext)  // 复制结点的下一个不为空
	{
		pNode->pNext = pClone->pNext;    // 两个链表重新指向对应的结点
		pNode = pNode->pNext;
		pClone->pNext = pNode->pNext;
		pClone = pClone->pNext;
	}

	// 达到最后 一个空结点
	pNode->pNext = pClone->pNext;
	pClone->pNext = NULL;

	return cpyHead;
}

ComplexListNode* Clone(ComplexListNode* pHead)    // 主调 函数
{
	CopyNode(pHead);
	CopySibling(pHead);
	return DivList(pHead;)
}

Q27 二叉搜索树转换成排序的双向链表

二叉搜索树从小到大输出应该是按左中右输出的;因此将树转换成双向链表也应该是先获得左子树的链表,并返回尾结点指针;
这时,将根结点与尾结点之间形成双向链表,将这里的尾结点传递到右子树中;
在右子树中的过程与前面的一样,递归完成;

void convert(BTreeNode* root,BTreeNode** pLastLinkNode)
{
	// 递归实现将左子树的链表与根结点相结合,并传递进右子树递归
	// *pLastLinkNode为已经指向的双向链表的尾结点
	if(root == NULL)
		return;

	if(root->left == NULL && root->right ==NULL) // 如果*pLastLinkNode已经指向了双向链表,则重新指向,否则直接赋值

	{
		if(*pLastLinkNode)
		{
			(*pLastLinkNode)->right = root;
			root->left = *pLastLinkNode;
		}
		*pLastLinkNode = root;
		return;
	}

	if(root->left != NULL) // 左子树不为空
		convert(root->left,pLastLinkNode);

	BTreeNode* pCur = root;
	// 当前结点与左子树结合
	root->left = *pLastLinkNode;
	(*pLastLinkNode)->right = root; 
	*pLastLinkNode = root;

	if(root->right != NULL)
		convert(root->right,pLastLinkNode);
}

BTreeNode* BTreeToDouLink(BTreeNode* root)    // left代表上一个结点,右代表下一个结点
{
	if(!root)
		return NULL;
	if(root->left == NULL && root->right == NULL)
		return root;

	// 多于一个结点
	BTreeNode* pLastLinkNode = NULL;
	convert(root,&pLastLinkNode);

	// pLastLinkNode该结点是双向链一有的最后一个结点,因此要获得头结点
	BTreeNode* pListHead = pLastLinkNode;
	while(pListHead->left != NULL)
		pListHead = pListHead->left;
	// 头尾结点的下一个置空
	pListHead->left = NULL;
	pLastLinkNode->right = NULL;
	return pListHead;
}

Q29 打印出字符串的所有排列或组合

递归:循环当前位置的字符,递归打印循环下一字符

排列相对来说简单,这里不给出,下面给出所有组合的输出(字符串中 没有相同的字符的情况下
组合
组合问题可以分解成这样:
长度为n的ch = "abcdef";打印m个字符的组成;
该问题可以分解成:
1. 组合中包含当前的字符串的第一个字符,后面将是在n-1个字符里先m-1个字符组合;
2. 组合中不包含当前的字符串中的第一个字符,后面将是在n-1个字符里先出m个字符组合;

string str = ""; // 一个全局变量来保存当前的组合
int num = 0;<span style="white-space:pre">	</span>// 用来保存组合的个数
// 将长度为n的字符串ch里的m个字符的组合打印出来
void PrintConbinatio(char* ch, int m)
{
	if(!ch || m < 0)  // 输入边界判断
		return;
	
	// 递归结束判断
	int len = strlen(ch);
	if(len < m)   // 剩余的字符串长度不够
		return;
	else if(len == m)  // 剩余的字符个数与还要打印的个数相等
	{
		cout<<str + ch<<"第"<<++num<<"个" <<endl;
		return;
	}
	else if(m == 0) // 所要打印的字符串长度已经够了
	{
		cout << str<<"第"<<++num<<"个" <<endl;
		return;
	}

	string s = str;
	str += *ch;
	PrintConbinatio(ch+1,m-1);  // 当前字符加入

	str = s;
	PrintConbinatio(ch+1,m);  // 当前字符不加入
}

int main()
{	
	char* str = "abcde";
	PrintConbinatio(str,3);
}









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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值