您的位置:首页 > Web前端

【剑指Offer】鸟瞰50题之11 - 20题

2014-07-09 23:11 323 查看
面试题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]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: