面试题三、数组中的查找
一个二维数组每行、每列都递增排序。输入一个数字,判断该数字是否在数组中。
/*
例:
1 2 8 9
2 4 9 12
4 7 10 13
6 8 11 15
若输入7则返回true
若输入5则返回false
*/
bool Find(int *matrix , int rows, int colums, int number)
{
bool found = false;
if (matrix != NULL && rows > 0 && columns > 0)
{
int row = 0;
int column = columns - 1;
while (row < rows && column >= 0)
{
if (matrix[row * columns + column] == number)
{
found = true;
break;
}
else if (matrix[row * columns + column] > numver)
-- columnn;
else
++ row;
}
}
return found;
}
面试题五、从尾到头打印链表
// 链表结点定义如下:
struct ListNode
{
int m_nKey;
ListNode* m_pNext;
};
// 解法一
// 思路:用栈
void PrintListReversingly_Iteratively(ListNode *pHead)
{
std::stack<ListNode*> nodes;//栈
ListNode* pNode = pHead;
while (pNode != NULL)
{
nodes.push(pNode);
pNode = pNode->m_pNext;
}
while (!nodes.empty())
{
pNode = nodes.top();
printf("%d\t",pNode->m_nValue);
nodes.pop();
}
}
// 解法二
// 思路:递归
// 缺点:有可能导致函数调用栈溢出
void PrintListReversingly_Recursively(ListNode *pHead)
{
if (pHead != NULL)
{
if (pHead->m_pNext != NULL)
{
PrintListReversingly_Recursively(pHead->m_pNext);
}
printf("%d\t",pHead->m_nValue);
}
}
面试题六、重建二叉树
根据前序遍历序列和中序遍历序列重建二叉树
struct BinaryTreeNode
{
int m_nValue;
BinaryTreeNode* m_pLeft;
BinaryTreeNode* m_pRight;
};
BinaryTreeNode* Construct(int *preorder, int *inorder,int length)
{
if (perorder == NULL || inoerder == NULL || length <= 0)
returen NULL;
return ConstructCore(perorder ,preorder + length - 1,inorder,inorder + length - 1);
}
BinaryTreeNode* ConstructCore(
int* startPreoder, int* endPreorder, int* startInorder ,int* endInorder)
{
// 前序遍历序列的第一个数字是根节点的值
int rootValue = startPreorder[0];
BinaryTreeNode* root = new BinaryTreeNode();
root->m_nValue = rootValue;
root->m_pLeft = root->m_pRight = NULL;
if (startPreorder == endPreorder)
{
if (startInorder == endInorder && *startPreorder == *startInorder)
return root;
else
throw std::exception("Invalid input.");
}
// 在中序遍历中找到根节点的值
int* rootInorder = startInoder;
while(rootInorder <= endInorder && *root Inorder != rootValue)
++ rootInorder;
if (rootInorder == endInorder && endInorder && *rootInorder != rootValue)
throw std::exception("Invalid input.");
int leftLength = rootInorder - startInorder;
int* leftPreorderEnd = startPreorder + leftLength;
if (leftLength > 0)
{
// 构建左子树
root->m_pLeft = ConstructCore(startPreorder + 1, leftPreorderEnd, startInorder, rootInorder - 1);
}
if (leftLength < endPreorder - startPreorder)
{
// 构建右子树
root->m_pRight = ConstructCore(leftPreorderEnd + 1, endPreorder, rootInorder + 1, endInorder);
}
return root;
}
面试题七、用两个栈实现队列
template <typename T> class CQueue
{
public:
CQueue(void);
~CQueue(void);
void appendTail(const T& node);
T deleteHead();
private:
stack<T> stack1;
stack<T> stack2;
};
-------------------------------------------
template<typename T> void CQueue<T>::appendTail(const T& element)
{
stack1.push(element);
}
template<typename T> T CQueue<T>::deleteHead()
{
if (stack2.size() <= 0)
{
while(stack1.size() > 0)
{
T& data = stack1.top();
stack1.pop();
stack2.push(data);
}
}
if (stack2.size() == 0)
throw new exception("queue is empty");
T head = stack2.top();
stack2.pop();
return head;
}
面试题八、旋转数组的最小数字
将某递增数组进行旋转,即{1,3,5,7,9}旋转后的结果之一为{7,9,1,3,5}
其最小数字为1
{9,1,3,5,7}
int Min(int* numbers, int length)
{
if (numbers == NULL || length <= 0)
throw new std::exception("Invalid parameters");
int index1 = 0;
int index2 = length - 1;
int indexMid = index1;
//当numbers[index1] < numbers[index2] 时,说明该数组没有旋转,还是递增。所以indexMid == index1 == 0,因为index1无论如何也不会大于index2
while (numbers[index1] >= numbers[index2])
{
if (index2 - index1 == 1)
{
indexMid = index2;
break;
}
indexMid = (index1 + index2) / 2;
if (numbers[indexMid] >= numbers[index1])
index1 = indexMid;
else if (numbers[indexMid] <= numbers[index2])
index2 = indexMid;
}
return numbers[indexMid];
}
面试题九、斐波那契数列
n==0时 f(n)==0;
n==1时 f(n)==1;
n>1时 f(n)==(f(n-1)+f(n-2));
// 递归会很低效,所以最好找出其他办法
//思路 : 先算f(2),再根据f(1)和f(2)算出f(3),然后以此类推算出f(n)
long long Fibonacci(unsigned n)
{
int result[2] = (0,1);
if(n < 2)
return result[n];
//这个写的好装逼啊
long long fibNMinusOne = 1;
long long fibNMinusTwo = 0;
long long fibN = 0;
for (unsigned int i =2 ; i <= n; ++ i)
{
fibN = fibNMinusOne + fibNMinusTwo;
fibNMinusTwo = fibNMinusOne;
fibNMinusOne = fibN;
}
return fibN;
}
面试题十、二进制中1的个数
int NumberOf1(int n)
{
int count = 0;
while (n)
{
++ count;
n = (n - 1) & n; // 每次这样的操作就会把最右面为1的位变成0,其他位不变
}
returen count;
}
1010100 - 1 = 1010011
1010100 & 1010011 = 1010000
1010000 - 1 = 1001111
1010000 & 1001111 = 1000000
1000000 - 1 = 0111111
1000000 & 0111111 = 0
面试题十二、打印1到最大的n位数
void Print1ToMaxOfNDigits(int n)
{
if (n <= 0)
return;
char *number = new char[n + 1];
memset(number, '0' , n);//将某一块内存中的内容全部设置为指定的值
number[n] = '\0';
while(!Increment(number))
{
PrintNumber(number);
}
delete []number;
}
bool Increment(char *number)//判断是否到了n位数
{
bool isOverflow = false;
int nTakeOver = 0;
int nLength = strlen(number);
for (int i = nLength - 1; i >= 0; i --)
{
int nSum = number[i] - '0' + nTakeOver;
if (i == nLength - 1)
nSum ++;
if (nSum >= 10)
{
if (i == 0)
isOverflow = true;
else
{
nSum -= 10;
nTakeOver = 1;
number[i] = '0' + nSum;
}
}
else
{
number[i] = '0' + nSum;
break;
}
}
return isOverflow;
}
void PrintNumber(char *number)
{
bool isBeginning0 = true;
int nLength = strlen(number);
for (int i = 0; i < nLength; ++ i)
{
if (isBeginning0 && number[i] != '0')
isBeginning0 = false;
if (!isBeginning0)
{
printf("%c", number[i]);
}
}
printf("\t");
}
面试题十三、在O(1)时间删除单向链表结点
struct ListNode
{
int m_nValue;
ListNode* m_pNext;
};
void DeleteNode(ListNode** pListHead,ListNode* pToBeDeleted)
{
if(!pListHead || !pToBeDeleted)
return;
// 要删除的结点不是尾结点
if (pToBeDeleted->m_pNext != NULL)
{
ListNode* pNext = pToBeDeleted->m_pNext;
pToBeDeleted->m_nValue = pNext->m_nValue;
pToBeDeleted->m_pNext = pNext->m_pNext;
delete pNext;
pNext = NULL;
}
// 链表只有一个结点,删除头结点(也是尾结点)
else if (*pListHead == pToBeDeleted)
{
delete pToBeDeleted;
pToBeDeleted = NULL;
*pListHead = NULL;
}
// 链表中有多个结点,删除尾结点
else
{
ListNode* pNode = *pListHead;
while(pNode->m_pNext != pToBeDeleted)
{
pNode = pNode->m_pNext;
}
pNode->m_pNext = NULL;
delete pToBeDeleted;
pToBeDeleted = NULL;
}
}
面试题十四、调整数组顺序使奇数位于偶数前面
void ReorderOddEven(int *pData,unsigned int length)
{
if (pData == NULL || length == 0)
return;
int *pBegin = pData;
int *pEnd = pData + length - 1;
while(pBegin < pEnd)
{
// 向后移动pBegin,直到它指向偶数
while(pBegin < pEnd && (*pBegin & 0x1) != 0)
pBegin ++;
// 向前移动 pEnd,直到它指向奇数
while (pBegin < pEnd && (*pEnd & 0x1) == 0)
pEnd --;
if (pBegin < pEnd)
{
int temp = *pBegin;
*pBegin = *pEnd;
*pEnd = temp;
}
}
}
// 升级版
void Reorder(int *pData, unsigned int length,bool (*func)(int))
{
if (pData == NULL || length == 0)
return;
int *pBegin = pData;
int *pEnd = pData + length - 1;
while (pBegin < pEnd)
{
while (pBegin < pEnd && !func(*pBegin))
pBegin ++;
while (pBegin < pEnd && func(*pEnd))
pEnd -- ;
if (pBegin < pEnd)
{
int temp = *pBegin;
*pBegin = *pEnd;
*pEnd = temp;
}
}
}
bool isEven(int n)
{
return (n & 1) == 0;
}
--------------------------------------
// 函数Reorder把数组pData分成两部分
// 函数isEven是一个具体的标准,即判断一个数是不是偶数,或是不是别的什么数
// 两函数一组合,可以实现各种分离
void ReorderOddEven(int *pData, unsigned int length)
{
Reorder(pData,length,isEven);
}
面试题十五、查找单向链表中倒数第K个结点
struct ListNode
{
int m_nValue;
ListNode* m_pNext;
};
ListNode* FindKthToTail(ListNode* pListHead, unsigned int k)
{
if (pListHead == NULL || k == 0)
return NULL;
ListNode *pAhead = pListHead;
ListNode *pBehind = NULL;
for (unsigned int i = 0; i < k - 1; ++ i)
{
if (pAhead->m_pNext != NULL)
pAhead = pAhead->m_pNext;
else
{
return NULL;
}
}
pBehind = pListHead;
while (pAhead->m_pNext != NULL)
{
pAhead = pAhead->m_pNext;
pBehind = pBehind->m_pNext;
}
return pBehind;
}
面试题十六、反转单链表
struct ListNode
{
int m_mKey;
ListNode* m_pNext;
};
ListNode* ReverseList(ListNode* pHead)
{
ListNode* pReversedHead = NULL;
ListNode* pNode = pHead;
ListNode* pPrev = NULL;
while (pNode != NULL)
{
ListNode* pNext = pNode->m_pNext;
if (pNext == NULL)
pReversedHead = pNode;
pNode->m_pNext = pPrev;
pPrev = pNode;
pNode = pNext;
}
return pReversedHead;
}
面试题十七、合并两个排序的链表
struct ListNode
{
int m_nValue;
ListNode* m_pNext;
};
ListNode* Merge(ListNode* pHead1,ListNode* pHead2)
{
if (pHead1 == NULL)
return pHead2;
else if (pHead2 == NULL)
return pHead1;
ListNode* pMergedHead = NULL;
// 递归
if (pHead->m_nValue < pHead2->m_nValue)
{
pMergedHead = pHead1;
pMergedHead->m_pNext = Merge(pHead1->m_pNext,pHead2);
}
else
{
pMergedHead = pHead2;
pMergedHead->m_pNext = Merge(pHead1,pHead2->m_pNext);
}
return pMergedHead;
}
面试题十八、树的子结构
题目:输入两棵二叉树A和B,判断B是不是A的子结构
struct BinaryTreeNode
{
int m_Valeue;
BinaryTreeNode* m_pLeft;
BinaryTreeNode* m_pRight;
};
// 递归判断子节点是否与B的根节点一样
bool HasSubtree (BinaryTreeNode* pRoot1,BinaryTreeNode* pRoot2)
{
bool result = false;
if (pRoot1 != NULL && pRoot2 != NULL)
{
if (pRoot->m_nValue == pRoot2->m_nValue)
result = DoesTree1HaveTree2(pRoot1,pRoot2);
if (!result)
result = HasSubtree(pRoot1->m_pLeft,pRoot2);
if (!result)
result = HasSubtree(pRoot1->m_pRight,pRoot2);
}
return result;
}
// 递归判断
bool DoesTree1HaveTree2(BinaryTreeNode* pRoot1,BinaryTreeNode* pRoot2)
{
if (pRoot2 == NULL)
return true;
if (pRoot1 == NULL)
return false;
if (pRoot1->m_nValue != pRoot2->m_nValue)
return false;
return DoesTree1HaveTree2(pRoot1->m_pLeft,pRoot2->m_pLeft) && DoesTree1HaveTree2(pRoot1->m_pRight,pRoot2->m_pRight);
}
面试题十九、二叉树的镜像
题目:请完成一个函数,输入一个二叉树,该函数输出它的镜像。(其实就是左右树反转)
struct BinaryTreeNode
{
int m_Valeue;
BinaryTreeNode* m_pLeft;
BinaryTreeNode* m_pRight;
};
void MirrorRecursively (BinaryTreeNode *pNode)
{
if ((pNode == NULL) || (pNode->m_pLeft == NULL && pNode->m_pRight))
return;
BinaryTreeNode *pTemp = pNode->m_pLeft;
pNode->m_pLeft = pNode->m_pRight;
pNode->m_pRight = pTemp;
if (pNode->m_pLeft)
MirrorRecursively(pNode->m_pLeft);
if (pNode->m_pRight)
MirrorRecursively(pNode->m_pRight);
}
面试题二十、顺时针打印矩阵
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
print:1、2、3、4、8、12、16、15、14、13、9、5、6、7、11、10
void PrintMatrixClockwisely(int** numbers,int columns,int rows)
{
if (numbers == NULL || columns <= 0 || rows <= 0)
return;
int start = 0;
while (columns > start * 2 && rows > start * 2)
{
PrintMatrixInCircle(numbers, columns ,rows ,start);
++start;
}
}
void PrintMatrixInCircle(int** numbers,int columns; int rows ,int start)
{
int endX = columns - 1 -start;
int endY = rows - 1 - start;
// 从左到右打印一行
for (int i = start ; i <= endX; ++i)
{
int number = numbers[start][i];
printNumber(number);
}
// 从上到下打印一列
if (start < endY)
{
for (int i = start + 1;i <= endY; ++i)
{
int numebr = number[i][endX];
printNumber(number);
}
}
// 从右到左打印一行
if (start < endX && start < endY)
{
for (int i = endX - 1;i >= start; --i)
{
int number = numbers[endY][i];
printNumber(number);
}
}
// 从下到上打印一行
if (start < endX && start > endY - 1)
{
for (int i = endY - 1;i >= start + 1; --i)
{
int number = numbers[i][start];
printNumber(number);
}
}
}
面试题二十一、包含min函数的栈
template <typename T> void StackWithMin<T>::push(const T& value)
{
m_data.push(value);
if (m_min.size() == 0 || value < m_min.top())
m_min.push(value);
else
m_min.push(m_min.top());
}
template <typename T> void StackWithMin<T>::pop()
{
assert(m_data.size() > 0 && m_min.size() > 0);
m_data.pop();
m_min.pop();
}
template <typename T> const T& StackWithMin<T>::min() const
{
assert(m_data.size() > 0 && m_min.size() > 0);
return m_min.top();
}
面试题二十二、栈的压入、弹出序列
bool IsPopOrder(const int* pPush,const int* pPop ,int nLength)
{
bool bPossible = false;
if (pPush != NULL && pPop != NULL && nLength > 0)
{
const int* pNextPush = pPush;
const int* pNextPop = pPop;
std::stack<int>stackData;
while (pNextPop - pPop < nLength)
{
while(stackData.empty() || stackData.top() != *pNextPop)
{
if(pNextPush - pPush == nLength)
break;
stackData.push(*pNextPush);
pNextPush++;
}
if (stackData.top() != *pNextPop)
break;
stackData.pop();
pNextPop ++;
}
if (stackData.empty() && pNextPop - pPop == nLength)
bPossible = true;
}
return bPossible;
}
面试题二十三、从上往下打印二叉树
struct BinaryTreeNode
{
int m_nValue;
BinaryTreeNode* m_pLeft;
BinaryTreeNode* m_pRight;
};
// 思路 : 左子树的子树一定在右子树的子树的前面,右子树在左子树的子树的前面
viod PrintFromTopBottom(BinaryTreeNode* pTreeRoot)
{
if(!pTreeRoot)
return;
std::deque<BinaryTreeNode *> dequeTreeNode;
dequeTreeNode.push_back(pTreeRoot);
while (dequeTreeNode.size())
{
BinaryTreeNode *pNode = dequeTreeNode.front();
dequeTreeNode.pop_front();
printf("%d ",pNode->m_nValue);
if (pNode->m_pLeft)
dequeTreeNode.push_back(pNode->m_pLeft);
if (pNode->m_pRight)
dequeTreeNode.push_back(pNode->m_pRight);
}
};
面试题二十四、二叉搜索树的后序遍历序列
bool VerifySquenceOfBST(int sequence[],int length)
{
if (sequence == NULL || length <= 0)
return false;
int root = sequence[length - 1];
// 在二叉搜索树中左子树的结点小于根结点
int i = 0;
for (;i < length - 1; ++ i)
{
if (sequence[i] > root)
break;
}
// 在二叉搜索树中右子树的结点大于根节点
int j = i;
for (; j < length - 1;++ j)
{
if (sequence[j] < root)
return false;
}
// 判断左子树是不是二叉搜索树
bool left = true;
if (i > 0)
left = VerifySquenceOfBST(sequence, i);
// 判断右子树是不是二叉搜索树
bool right = true;
if (i < length - 1)
right = VerifySquenceOfBST(sequence + i, length - i - 1);
return (left && right);
}
面试题二十五、二叉树中和为某一值的路径
struct BinaryTreeNode
{
int m_nValue;
BinaryTreeNode* m_pLeft;
BinaryTreeNode* m_pRight;
};
void FindPath(BinaryTreeNode* pRoot, int expectedSum)
{
if (pRoot == NULL)
return;
std::verctor<int> path;
int currentSum = 0;
FindPath(pRoot,expectedSum, path,currentSum);
}
void FindPath(BinaryTreeNode* pRoot, int expectedSum, std::vector<int>& path, int& currentSum)
{
currentSum += pRoot->m_nValue;
path.push_back(pRoot->m_nVlaue);
// 如果是叶节点,并且路径上结点的和等于输入的值
// 打印出这条路径
bool isLeaf = pRoot->m_pLeft == NULL && pRoot->m_pRight == NULL;
if (currentSum == expectedSum && isLeaf)
{
printf("A path is found: ");
std::verctor<int >::iterator iter = path.begin();
for (; iter != path.end(); ++ iter)
printf("%d\t",iter);
printf("\n");
}
// 如果是不是叶结点,则遍历它的子节点
if (pRoot->m_pLeft != NULL)
FindPath(pRoot->m_pLeft, expectedSum, path, currentSum);
if (pRoot->m_pRight != NULL)
FindPath(pRoot->m_pRight, expectedSum, path, currentSum);
// 在返回到父节点之前,在路径上删除当前结点,
// 并在currentSum中减去当前结点的值
currentSum -= pRoot->m_nVlaue;
path.pop_back();
}
面试题二十六、复杂链表的复制
// 第一步:将原结点逐一复制并紧贴原结点之后
void CloneNodes(ComplexListNode* pHead)
{
ComplexListNode* pNode = pHead;
while(pNode != NULL)
{
ComplexListNode* pCloned = new ComplexListNode();
pCloned->m_nValue = pNode->m_nValue;
pCloned->m_pNext = pNode->m_pNext;
pCloned->m_pSibling = NULL;
pNode->m_pNext = pCloned;
pNode = pCloned->m_pNext;
}
}
// 第二步:将原结点的第二指向给复制的结点
void ConnectSiblingNodes(ComplexListNode* pHead)
{
ComplexListNode* pNode = pHead;
while(pNode != NULL)
{
ComplexListNode* pCloned = pNode->m_pNext;
if(pNode->m_pSibling != NULL)
{
pCloned->m_pSibling = pNode->m_pSibling->m_pNext;
}
pNode = pCloned->m_pNext;
}
}
// 第三步:分离
ComplexListNode* ReconnectNodes(ComplexListNode* pHead)
{
ComplexListNode* pNode = pHead;
ComplexListNode* pClonedHead = NULL;
ComplexListNode* pClonedNode = NULL;
if (pNode != NULL)
{
pClonedHead = pClonedNode = pNode->m_pNext;
pNode->m_pNext = pClonedNode->m_pNext;
pNode = pNode->m_pNext;
}
while (pNode != NULL)
{
pClonedNode->m_pNext = pNode->m_pNext;
pClonedNode = pClonedNode->m_pNext;
pNode->m_pNext = pClonedNode->m_pNext;
pNode = pNode->m_pNext;
}
return pClonedHead;
}
ComplexListNode* Clone(ComplexListNode* pHead)
{
CloneNodes(pHead);
ConnectSiblingNodes(pHead);
return ReconnectNodes(pHead);
}
面试题二十七、二叉搜索树与双向链表
BinaryTreeNode* Convert(BinaryTreeNode* pRootOfTree)
{
BinaryTreeNode *pLastNodeInList = NULL;
ConvertNode(pRootOfTree, &pLastNodeInList);
// pLastNodeInList 指向双向链表的尾结点
// 我们需要返回头结点
BinaryTreeNode* pHeadOfList = pLastNodeInList;
while (pHeadOfList != NULL && pHeadOfList->m_pLeft != NULL)
pHeadOfList = pHeadOfList->m_pLeft;
return pHeadOfList;
}
void ConvertNode(BinaryTreeNode* pNode,BinaryTreeNode** PLastNodeInlist)
{
if (pNode == NULL)
return;
BinaryTreeNode *pCurrent = pNode;
// 递归至最左子结点
if (pCurrent->m_pLeft != NULL)
ConvertNode(pCurrent->m_pLeft,pLastNodeInList);
// 最左子节点的父节点的左结点为最左子节点的父节点的左结点
pCurrent->m_pLeft = *pLastNodeInList;
if (*pLastNodeInList != NULL) //*pLastNodeInList 不为空代表该次循环不是最左子节点
(*pLastNodeInList)->m_pRight = pCurrent; //说明当前结点比上一次递归的值大,应该在上次结点的右边;如果是右子树递归进来的则实际上是重复赋值了
*pLastNodeInList = pCurrent;// 在递归右子树前,将当前结点存入,保证每次递归pLastNodeInList一定比pCurrent小
if (pCurrent->m_pRight != NULL)
ConvertNode(pCurrent->m_pRight,pLastNodeInList);
// 总结:
// pCurrent->m_pLeft = *pLastNodeInList 和 (*pLastNodeInList)->m_pRight = pCurrent 说明pCurrent一定要比*pLastNodeInList大
}
//感悟递归:假设某个方法可以递归,再去尝试写递归的最后一步
//此题感悟:需要借助一个空的参数,即*pLastNodeInList,代表上一次递归的结点,且上一个结点一定要小于当前结点
// 二叉树的递归:可不可以分别只考虑只有左子树与只有右子树的情况?
面试二十八、字符串的排列
void Permutation(char* pStr)
{
if (pStr == NULL)
return;
Permutation(pStr,pStr);
}
void Permutation(char* pStr,char* pBegin)
{
if (*pBegin == '\0')
{
printf("%s\n",pStr);// 下方for循环到最后一个字母的时候打印
}
else
{
// pCh为当前递归中小循环的字母
for (char* pCh = pBegin; *pCh != '\0'; ++ pCh)
{
char temp = *pCh;//
*pCh = *pBegin;//
*pBegin = temp; //
// 将当前小循环的字母的值 与 将当前小循环的字母的值 互换
Permutation(pStr,pBegin + 1);
// 传递正常字符串和原字符串去掉第一个字母的字符串到下一层递归
// 当pBegin + 1 == '\0' 时,打印当前的pStr
//由于前面交换了一下,所以pCh的内容改变了,我们要还原回来
temp = *pCh;
*pCh = *pBegin;
*pBegin = temp;
}
}
}
面试二十九、数组中出现次数超过一半的数字
int MoreThanHalfNum(int* numbers, int length)
{
if (CheckInvalidArray(numbers,length))
return 0;
int middle = length >> 1;
int start = 0;
int end = length - 1;
int index = Partition(numbers, length, start, end);
while (index != middle)
{
if (index > middle)
{
end = index - 1;
index = Partition(numbers, length, start, end);
}
else
{
start = index + 1;
index = Partition(numbers, length, start, end);
}
}
int result = numbers[middle];
if (!CheckMoreThanHalf(numbers, length, result))
result = 0;
return result;
}
int Partition(int data[], int length, int start,int end)
{
if (data == NULL || length <= 0 || start < 0 || end >= length)
throw new std::exception("Invalid Parameters");
int index = RandomInRange(start, end);
Swap(&data[index], &data[end]);
int small = start - 1;
for (index = start; index < end; ++ index)
{
if (data[index] < data[end])
{
++ small;
if (small != index)
}
}
++ small;
Swap(&data[small], &data[end]);
return small;
}
bool g_bInputInvalid = false;
bool CheckInvalidArray (int* numbers, int length)
{
g_bInputInvalid = false;
if (numbers == NULL && length <= 0)
g_bInputInvalid = true;
return g_bInputInvalid;
}
bool CheckMoreThanHalf(int* numbers, int length, int number)
{
int times = 0;
for(int i =0; i < length; ++ i)
{
if (numbers[i] == number)
times++;
}
bool isMoreThanHalf = true;
if( times * 2 <= length)
{
g_bInputInvalid = true;
isMoreThanHalf = false;
}
return isMoreThanHalf;
}
// 第二种解法:
// 如果数组中有一个数字出现的次数超过数组长度的一半,也就是说它出现的次数比其他所有数字出现次数的和还要多。
int MoreThanHalfNum(int* numbers,int length)
{
if (CheckInvalidArray(numbers, length))
return 0;
int result = numvers[0];//保存数组中的一个值
int times = 1;//记这个值出现的次数
for (int i = 1; i < length; ++ i)
{
if (times == 0) // 当次数为0时
{
result = numbers[i];
times = 1;
}
else if (numbers[i] == result)
times ++;//如果下一个值与之前记录的值相同则次数+1
else
times--;//如果下一个值与之前记录的值不同则次数-1
}
if (!CheckMoreThanHalf(numbers,length,result))
result = 0;
return result;
}
面试三十、最小的k个数
输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。
void GetLeastNumbers(int* input , int n ,int* output,int k)
{
if (input == NULL || output == NULL || k > n || n <= 0 || k <= 0)
return;
int start = 0;
int end = n - 1;
int index = Partition(input , n ,start ,end);
while(index != k - 1)
{
if (index > k - 1)
{
end = index - 1;
index = Partition(input, n , start ,end);
}
else
{
start = index + 1;
index = Partition (input , n ,start ,end);
}
}
for (int i = 0; i < k)
output[i] = input[i];
}
如果面试官要求不能修改数组该怎么办?
解法二:O(nlogk)的算法,特别适合处理海量数据
typedef multtiset<int , greater<int> > intSet;
typedef multtiset<int , greater<int> >::iterator setIterator;
void GetLeastNumbers(const vector<int>& data, intSet& leastNumbers, int k)
{
leastNumbers.clear();
if (k < 1 || data.size() < k)
return;
vector<int>::const_iterator iter = data.begin();
for (; iter != data.end(); ++ iter)
{
if ((leastNumbers.size()) < k)
leastNumbers.insert(*iter);
else
{
setIterator itGreatest = leastNumbers.begin();
if (*iter < *(leastNumber.begin()))
{
leasetNumbers.erase(iterGreatest);
leasetNumbers.insert(*iter);
}
}
}
}
面试题31:连续子数组的最大和
bool g_InvalidInput = false;
int FindGreatestSumOfSubArray(int *pData,int nLength)
{
if ((pData == NULL) || (nLength <= 0))
{
g_InvalidInput = true;
return 0;
}
g_InvalidInput = false;
int nCurSum = 0;
int nGreatestSum = 0x80000000;//负数的最小值
for (int i = 0;i < nLength; ++i)
{
if (nCurSum <= 0)
nCurSum = pData[i];
else
nCurSum += pData[i];
if (nCurSum > nGreatestSum)
nGreatestSum = nCurSum;
}
return nGreatestSum;
}
面试题三十二、从1到n整数中1出现的次数
int NumberOf1Between1AndN(int n)
{
if (n <= 0)
return 0;
char strN[50];
sprintf(strN,"%d",n);
return NumberOf1(strN);
}
int NumberOf1(const char* strN)
{
if (!strN || *strN < '0' || *strN > '9' || *strN == '\0')
return 0;
int first = *strN - '0';
unsigned int length = statuc_cast<unsigned int>(strlen(strN));
if(length == 1 && first == 0)
return 0;
if(length == 1 && first > 0)
return 1;
// 假设strN是"21345"
// numFirstDigit是数字10000 ~ 19999的第一个位中的数目
int numFirstDigit = 0;
if (first > 1)
numFirstDigit = PowerBase10(length - 1);
else if (first == 1)
numFirstDigit = atoi(strN + 1) + 1;//是把字符串转换成整型数的一个函数
// numFirstDigits 是1346~21345除了第一位之外的数位中的数目
int numFirstDigits = first * (length - 1) * PowerBase10(length - 2);
// numRecursive = NumverOf1(strN + 1);
return numFirstDigit + numOtherDigits + numRecursive;
}
int PowerBase10(unsigned int n)
{
int result = 1;
for (unsigned int i = 0; i < n; ++ i)
result *= 10;
return result;
}
面试题三十三、把数组排成最小的数
输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。
const int g_MaxNumberLength = 10;
char* g_StrCombine1 = new char[g_MaxNumberLength * 2 + 1];
char* g_StrCombine2 = new char[g_MaxNumberLength * 2 + 1];
void PrintMinNumber(int* numbers, int length)
{
if (numbers == NULL || length <= 0)
return;
char** strNumbers = (char**)(new int[length]);
for(int i = 0; i < length; ++i)
{
strNumbers[i] = new char[g_MaxNumberLength + 1];
sprintf(strNumbers[i],"%d", numbers[i]);
}
qsort(strNumbers, length, sizeof (char*),compare);
for (int i = 0;i < length; ++ i)
printf("%s",strNumbers[i]);
printf("\n");
for(int i = 0;i < length; ++ i)
delete[] strNumbers[i];
delete[] strNumbers;
}
int compare(const void* strNumber1, const void* strNumber2)
{
strcpy(g_StrCombine1, *(const char**)strNumber1);
strcpy(g_StrCombine1, *(const char**)strNumber2);
strcpy(g_StrCombine2, *(const char**)strNumber2);
strcpy(g_StrCombine2, *(const char**)strNumber1);
return strcmp(g_StrCombine1,g_StrCombine2);
}