面试题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]