【剑指Offer】俯视50题之11 - 20题

面试题11 数值的整数次方 
面试题12 打印1到最大的N位数 
面试题13 在O(1)时间删除链表结点 
面试题14 调整数组顺序使奇数位于偶数前面 
面试题15 链表中倒数第k个结点 
面试题16 反转链表  
面试题17 合并两个排序的链表 
面试题18 树的子结构  
面试题19 二叉树的镜像  
面试题20 顺时针打印矩阵

面试题11 数值的整数次方 实现函数 double pow(double bas,int exponent),求base的exponent次方,不得使用库函数。

代码例如以下:

int IsZero(double bas)
{
	if((bas-0.0 < 0.0000001) && (bas-0.0 > -0.0000001 ))
		return 1;
	return 0;
}
double pow(double bas,int exponent)
{
	int iSymbol = 1;
	double Result = 1;
	if (IsZero(bas) && exponent < 0)
	{
		throws exception;
	}
	
	if (exponent < 0)
	{
		iSymbol = -1;
		exponent = -exponent
	}

	while(exponent)
	{
		Result = Result*bas;
		exponent--;
	}

	if (iSymbol == 1)
		return Result;
	else
		return 1/Result;
	
}
优化之后的代码例如以下:

<pre name="code" class="html">int IsZero(double bas)
{
	if((bas-0.0 < 0.0000001) && (bas-0.0 > -0.0000001 ))
		return 1;
	return 0;
}
double pow_Exponent(double bas, int exponent)
{
	if (exponent == 0)
		return 1;
	if (exponent == 1)
		return bas;

	double result = pow_Exponent(bas,exponent>>1);
	result = result*result;

	if (exponent & 0x1 == 1) /* 假设最后一位是1*/
		result = result * bas;
	return result;
	
}
double pow(double bas,int exponent)
{
	int iSymbol = 1;
	double Result;
	if (IsZero(bas) && exponent < 0)
	{
		throws exception;
	}
	
	if (exponent < 0)
	{
		iSymbol = -1;
		exponent = -exponent
	}

	Result = pow_Exponent(bas, exponent);

	if (iSymbol == 1)
		return Result;
	else
		return 1/Result;
	
}



面试题12打印1到最大的N位数。输入一个整数n,则打印从1到n位数999…9之间的数

实现例如以下:

#include <iostream>
void printN(int iArray[], int n)
{ 
	int i = 0;
	while(iArray[i] == 0) 
	{
		i++;
	}
	for (; i < n; i++)
	{
		printf("%d",iArray[i]); 
	}
	printf("\n");
}
void PrintNum(int iArray[], int n, int iIndex) 
{
	if (iIndex == n)
	{
		printN(iArray,n);
		return;  /* 函数出口。切记 */
	}

	for (int i = 0; i <= 9; i++)
	{
		iArray[iIndex] = i;
		PrintNum(iArray, n, iIndex + 1); 
	}
}
int main()
{
	int iArray[3] = {0,0,0};
	PrintNum(iArray, 2, 0);
}

面试题13在O(1)时间删除链表结点 

实现例如以下:

struct ListNode
{
	int   m_nValue;
	ListNode  *m_pNext;
};
void DeleteNode(ListNode **pListHead, ListNode *pToBeDeleted)
{
	ListNode *pToBeDeletedTemp;

	if (pToBeDeleted == NULL || pListHead == NULL) 
		return;
	
	if (pToBeDeleted->m_pNext != NULL)
	{
		pToBeDeletedTemp = pToBeDeleted->m_pNext;
		pToBeDeleted->m_nValue = pToBeDeletedTemp->m_nValue;
		pToBeDeletedTemp = pToBeDeletedTemp->m_pNext;
		free(pToBeDeletedTemp);
	}
	else if(*pListHead == pToBeDeleted)/* 仅仅有一个结点*/
	{
		*pListHead = NULL;
		free(pToBeDeleted);
	}
	else /*最后一个结点。且含有多个结点的链表*/
	{
		pToBeDeletedTemp = *pListHead;
		while(pToBeDeletedTemp ->m_pNext != pToBeDeleted)
		{
			pToBeDeletedTemp++;
		}
		pToBeDeletedTemp->m_pNext = NULL;
		free(pToBeDeleted);	
	}
}
注意:

1. 考虑多个场景,分别进行处理

2. 记得释放删除结点的内存

面试题14  调整数组顺序使奇数位于偶数前面 

思路:左右两个指针,左边假设是奇数则后移,右边假设是偶数则前移,然后交换顺序,直到遍历完数组。

实现例如以下:

void ReOrderOddEven(int iArray[],int n)
{
	int iBegin = 0;
	int iEnd = n - 1;
	int iTemp;

	while(iBegin < iEnd)
	{
		while(iBegin < iEnd && iArray[iBegin]%2 != 0)/*奇数*/
		{
			iBegin++;
		}
		while(iBegin < iEnd && iArray[iEnd]%2 == 0)/*偶数*/
		{
			iEnd--;
		}

		if(iBegin < iEnd)
		{
			iTemp = iArray[iBegin];
			iArray[iBegin] = iArray[iEnd];
			iArray[iEnd] = iTemp;
		}
	}

	for (iBegin = 0; iBegin < n; iBegin++)
	{
		printf(" %d",iArray[iBegin]);
	}
	printf("\n");
}
注意:

1. 假设方便扩展,则将推断条件抽象出一个函数,假设是奇数 == > Fun(n) 。不是奇数 ==> !Fun(n)

面试题15 链表中倒数第k个结点 

实现例如以下:

struct ListNode
{
	int m_nValue;
	ListNode *m_pNext;
}
ListNode * FindKFromTail(ListNode *pListHead, unsigned int k)
{
	unsigned int num = k;
	ListNode *pList1 = pListHead;
	ListNode *pList2 = pListHead;

	if (pListHead == NULL || k == 0)
		return NULL;

	while(pList2->m_pNext != NULL && num - 1 != 0)
	{
		pList2 = pList2->m_pNext;		
	}

	if (num != 0)
	{
		return NULL;
	}

	while(pList2)
	{
		pList1 = pList1->m_pNext;
		pList2 = pList2->m_pNext;
	}

	return pList1;
	
}
注意:

1. 注意函数的鲁棒性

面试题16 反转链表 。定义一个函数。输入链表的头结点,翻转链表之后。返回翻转之后的链表的头结点。

实现例如以下:

struct ListNode
{
	int m_nValue;
	ListNode *m_pNext;
}
ListNode * ReverseList(ListNode *pListHead)
{
	ListNode *pListFront = pListHead;
	ListNode *pListNow = NULL;
	ListNode *pNext = NULL;

	if (pListFront == NULL)
	{
		return pListHead;
	}

	pListNow = pListFront->m_pNext;
	while (pListNow)
	{
		pNext = pListNow->m_pNext;
		pListNow->m_pNext = pListFront;

		pListFront = pListNow;
		pListNow = pNext;
	}
	return pListNow;
	
}

面试题17合并两个排序的链表 。链表中没有反复的数字,且递增排列。

实现例如以下:

struct ListNode
{
	int m_nValue;
	ListNode *m_pNext;
}
ListNode * Merge(ListNode *pListHead1, ListNode *pListHead2)
{
	ListNode *pListHead;

	if (pListHead1 == NULL)
		return pListHead2;
	else if (pListHead2 == NULL)
		return pListHead1;

	if (pListHead1->m_nValue < pListHead2->m_nValue)
	{
		pListHead = pListHead1;
		pListHead->m_pNext = Merge(pListHead1->m_pNext,pListHead2);
	}
	else if (pListHead1->m_nValue > pListHead2->m_nValue)
	{
		pListHead = pListHead2;
		pListHead->m_pNext = Merge(pListHead2->m_pNext,pListHead1);
	}
	return pListHead;
}

注意:

1. 注意使用递归思想考虑问题

面试题18  树的子结构 。给定两个树A和B,推断A是否是B的子结构,即B的某部分能够全然构成A

思路:

首先,推断从B中找到A的根节点

然后,递归比較B中该节点下面是否与A全然否相等。直到遍历完A为止。

实现例如以下:

struct BinaryTreeNode
{
	int data;
	BinaryTreeNode *lchild;
	BinaryTreeNode *rchild;
};

bool IsEqualTree(BinaryTreeNode *rootA, BinaryTreeNode *rootB)
{
	
	if (rootB == NULL)
	{
		return true;
	}
	else if (rootA == NULL)
	{
		return false;
	}
	else if (rootA->data != rootB->data)
	{
		return false;
	}

	return   (IsEqualTree(rootA->lchild, rootB->lchild)) && (IsEqualTree(rootA->rchild, rootB->rchild));
	
}
bool IsSubTree(BinaryTreeNode *rootA, BinaryTreeNode *rootB)
{
	bool result = false;

	if (rootA == NULL || rootB == NULL)
	{
		return result;
	}

	if (rootA->data == rootB)
	{
		result == IsEqualTree(rootA,rootB);
	}

	if (result == false)
	{
		result = IsSubTree(rootA->lchild, rootB);
	}

	if (rusult == false)
	{
		result = IsSubTree(rootA->rchild, rootB);
	}

	return result;
}

面试题19  二叉树的镜像 


两个互为镜像的二叉树,给一个数的根节点,将该二叉树转化为镜像二叉树


struct BinaryTreeNode
{
	int data;
	BinaryTreeNode *lchild;
	BinaryTreeNode *rchild;
};

void MirrorTree(BinaryTreeNode *root)
{
	BinaryTreeNode *temp;
	if (root == NULL)
	{
		return;
	}

	MirrorTree(root->lchild);
	MirrorTree(root->rchild);
	temp = root->lchild;
	root->lchild = root->rchild;
	root->rchild = temp;
}

void MirrorTree(BinaryTreeNode * root)
{
	BinaryTreeNode *temp;
	if (root == NULL)
	{
		return;
	}

	stack<BinaryTreeNode *> iStack;
	iStack.insert(root);
	while(iStack.size())
	{
		if (root->lchild != NULL)
		{
			iStack.insert(root->lchild);
		}
		if (root->rchild != NULL)
		{
			iStack.insert(root->rchild);
		}

		temp = iStack->top()->lchild;
		iStack->top()->lchild = iStack->top()->rchild;
		iStack->top()->rchild = temp;
		iStack.pop();
	}
}

面试题20  顺时针打印矩阵 

难点在于二维数组作为入參

实现例如以下:

#include <iostream>
/*
	从左到右输出数组,从上到下输出数组元素
*/
void LToR_UToD(int *a, int iBeginA, int iBeginB, int iEndA, int iEndB,int n)
{
	for (int i=iBeginB; i <= iEndB;++i)
		printf(" %d",a[iBeginA*n + i]);

	for (int j = iBeginA + 1; j <= iEndA; j++)
		printf(" %d", a[j*n + iEndB]);

}

/*
	从右到左输出数组,从下到上输出数组元素
*/
void RToL_DToU(int *a, int iBeginA, int iBeginB, int iEndA, int iEndB,int n)
{
	for (int i=iEndB; i >= iBeginB;--i)
		printf(" %d",a[iEndA*n + i]);
	for (int j = iEndA - 1; j >= iBeginA; --j)
		printf(" %d", a[j*n + iBeginB]);
}


int main()
{
	int a[][2]={{1,2},{3,4}};

	int iBeginA = 0;
	int iBeginB = 0;
	int iEndA = 1;
	int iEndB = 1;
	while(iBeginA <= iEndA && iBeginB <= iEndB)
	{
		LToR_UToD((int *)a, iBeginA++, iBeginB, iEndA, iEndB--, 2);

		RToL_DToU((int *)a, iBeginA, iBeginB++, iEndA--, iEndB, 2);
	}
	printf("\n");
} 

注意:

1. 二维数组作为入參数。怎样传递。

强制转化为指针

Func(a[][10])  作为一个数组的形式传入

        2. 对于一个m行n列的一个数组,a[i][j] 能够用指针表示为 a[i*n + j]


posted on 2017-05-07 15:41  ljbguanli  阅读(119)  评论(0编辑  收藏  举报