剑指offer——新增面试题
1. 数组
面试题51:数组中重复的数字(数组元素在0~n-1范围内)
bool duplicate(int numbers[],int length,int* duplication)
{
if (numbers == NULL || length <= 0)
return false;
for (int i=0;i<length;++i)
if (numbers[i] < 0 || numbers[i] > length-1)
return false;
for (int i=0;i<length;++i)
{
while (numbers[i] != i)
{
if (numbers[i] == numbers[numbers[i]])
{
*duplication == numbers[i];
return true;
}
int temp = numbers[i];
numbers[i] = numbers[temp];
numbers[temp] = temp;
}
}
return false;
}
面试题52:构建乘积数组(数组A[0,1,…,n-1]—>数组B,B[i]=A的元素相乘除了A[i])
void multiply(const vector<double>& array1,vector<double>& array2)
{
int length1 = array1.size();
int length2 = array2.size();
if (length1 == length2 && length2>1)
{
array2[0] = 1;
for (int i=0; i<length; ++i)
{
array2[i] = array2[i-1] * array1[i-1];
}
double temp = 1;
for (int i=length1-2;i>=0;--i)
{
temp *= array1[i+1];
array2[i] *=temp;
}
}
}
2. 字符串
面试题53:正则表达式匹配
bool match(char* str,char* pattern)
{
if (str == NULL || pattern == NULL)
return false;
return matchCore(str,pattern);
}
bool matchCore(char* str, char* pattern)
{
if (*str == '\0' && *pattern == '\0')
return true;
if (*str != '\0' && *pattern == '\0')
return false;
if (*(pattern+1) == '*')
{
if (*pattern == *str || (*pattern == '.' && *str != '\0'))
return matchCore(str+1,pattern+2) ||
matchCore(str+1,pattern) ||
matchCore(str,pattern+2);
else
return matchCore(str,pattern+2);
}
if (*str == *pattern || (*pattern =='.' && *str != '\0'))
return macthCore)str+1,pattern+1);
return false;
}
面试题54:表示数值的字符串
bool IsNumberic(char* string)
{
if (string == NULL)
return false;
if (*string == '+' || *string == '-')
++string;
if (string == '\0')
return false;
bool numberic = true;
scanDigits(&string);
if (*string != '\0')
{
if (*string == '.')
{
++string;
scaDigits(&string);
if (*string == 'e' || *string == 'E')
numeric = isEcponential(&string);
}
else if (*string == 'e' || *string == 'E')
numberic = isEcponential(&string);
else
numberic = false;
}
return numberic && *string == '\0'
}
void scanDigits(char** string)
{
while (**string != '\0' && **string >= '0' && **string <= '9')
++(*string);
}
bool isExponential(char** string)
{
if (**string != 'e' && **string != 'E')
return false;
++(*string);
if (**string == '+' || **string == '-')
++(*string);
if (**string == '\0')
return false;
scanDigits(string);
return (**string == '\0') ? true:false;
}
面试题55:字符流中第一个不重复的字符
class CharStatics
{
private:
int occurrence[256];
int index;
public:
CharStatics():index(0)
{
for (int i=0;i<256;++i)
occurrence[i] = -1;
}
void Insert(char ch)
{
if (occurrence[ch] == -1)
occurrence[ch] = index;
else if (occurrence[ch] >=0)
occurrence[ch] = -2;
index++;
}
char FirstAppera()
{
char ch = '\0';
int minIndex = numeric_limits<int>::max();
for (int i=0;i<256;++i)
{
if (occurrence[i] >= 0 && occurrence[i] < minIndex)
{
ch = (char)i;
minIndex = occurrence[i];
}
}
return ch;
}
}
3. 链表
面试题56:链表中环的入口结点
/*1.定义快慢指针,找到环中任意一个结点;
2.计算环的长度length;
3.在定义快慢指针,先让快指针走length步,在让慢指针走。直到两个指针相等时,即为入口节点;
复杂度为O(n);*/
ListNode* EntryNodeOfLoop(ListNode* pHead)
{
ListNode *meetNode = meetingNode(pHead);
if (meetNode == NULL)
return NULL;
int loopLength = 1;
ListNode *pNode1 = meetNode->next;
while (pNode1 != meetNode)
{
++loopLength;
pNode1 = pNode1->next;
}
pNode1 = pHead;
ListNode *pNode2 = pHead;
for (int i = 0; i<loopLength; i++)
pNode1 = pNode1->next;
while (pNode1 != pNode2)
{
pNode1 = pNode1->next;
pNode2 = pNode2->next;
}
return pNode1;
}
ListNode* meetingNode(ListNode *pHead)
{
if (pHead == NULL)
return NULL;
ListNode *pSlow = pHead->next;
if (pSlow == NULL)
return NULL;
ListNode *pFast = pSlow->next;
while (pFast != NULL && pSlow != NULL)
{
if (pFast == pSlow)
return pFast;
pSlow = pSlow->next;
pFast = pFast->next;
if (pFast != NULL)
pFast = pFast->next;
}
return NULL;
}
面试题57:删除排序链表中重复的结点
void deleteDuplication(ListNode** pHead)
{
if (pHead == NULL || *pHead == NULL)
return;
ListNode* pPreNode = NULL;
ListNode* pNode = *pHead;
while (pNode != NULL)
{
ListNode* pNext = pNode->m_pNext;
bool needDelete = false;
if (pNext != NULL && pNode->m_nValue == pNext->m_nValue)
needDelete = true;
if (!needDelete)
{
pPreNode = pNode;
pNode = pNode->m_pNext;
}
else
{
int value = pNode->m_nValue;
ListNode* pToBeDel = pNode;
while (pToBeDel != NULL && pToBeDel->m_nValue = value)
{
pNext = pToBeDel->m_pNext;
delete pToBeDel;
pToBeDel = NULL;
pToBeDel = pNext;
}
if (pPreNode == NULL)
*pHead = pNext;
else
pPreNode->m_pNext = pNext;
pNode = pNext;
}
}
}
4.树
面试题58:二叉树的下一个结点
BinaryTreeNode* GetNext(BinaryTreeNode* pNode)
{
if (pNode == NULL)
return NULL;
BinaryTreeNode* pNext = NULL;
if (pNode->m_pRight != NULL)
{
BinaryTreeNode* pRight = pNode->m_pRight;
while (pRight->m_pLeft != NULL)
pRight = pRight->m_pLeft;
pNext = pRight;
}
else if (pNode->m_pParent != NULL)
{
BinaryTreeNode* pCurrent = pNode;
BinaryTreeNode* pParent = pNode->m_pParent;
while (pParent != NULL && pCurrent == pParent->m_pParent)
{
pCurrent = pParent;
pParent = pParent->m_pParent;
}
pNext = pParent;
}
return pNext;
}
面试题59:对称的二叉树
bool isSymmetrical(TreeNode* pRoot)
{
return isSymmetrical(pRoot, pRoot);
}
bool isSymmetrical(TreeNode *pRoot1, TreeNode *pRoot2)
{
if (pRoot1 == NULL && pRoot2 == NULL)
return true;
if (pRoot1 == NULL || pRoot2 == NULL)
return false;
if (pRoot1->val != pRoot2->val)
return false;
return isSymmetrical(pRoot1->left, pRoot2->right)
&& isSymmetrical(pRoot1->right, pRoot2->left);
}
面试题60:把二叉树打印成多行
vector<vector<int> > Print(TreeNode* pRoot)
{
vector<vector<int> > result;
if (pRoot == NULL)
return result;
std::queue<TreeNode*> nodes;
nodes.push(pRoot);
int nextLevel = 0;
int toBePrinted = 1;
vector<int> oneRow;
while (!nodes.empty())
{
TreeNode* pNode = nodes.front();
oneRow.push_back(pNode->val);
if (pNode->left != NULL)
{
nodes.push(pNode->left);
++nextLevel;
}
if (pNode->right != NULL)
{
nodes.push(pNode->right);
++nextLevel;
}
nodes.pop();
--toBePrinted;
if (toBePrinted == 0)
{
result.push_back(oneRow);
oneRow.clear();
toBePrinted = nextLevel;
nextLevel = 0;
}
}
return result;
}
面试题61:按之字形顺序打印二叉树
vector<vector<int> > Print(TreeNode* pRoot)
{
vector<vector<int> > result;
if (pRoot == NULL)
return result;
stack<TreeNode*> levels[2];
int current = 0;
int next = 1;
levels[current].push(pRoot);
vector<int> oneRow;
while (!levels[0].empty() || !levels[1].empty())
{
TreeNode *pNode = levels[current].top();
levels[current].pop();
oneRow.push_back(pNode->val);
if (current == 0)
{
if (pNode->left != NULL)
levels[next].push(pNode->left);
if (pNode->right != NULL)
levels[next].push(pNode->right);
}
else
{
if (pNode->right != NULL)
levels[next].push(pNode->right);
if (pNode->left != NULL)
levels[next].push(pNode->left);
}
if (levels[current].empty())
{
result.push_back(oneRow);
oneRow.clear();
current = 1 - current;
next = 1 - next;
}
}
return result;
}
面试题62:序列化二叉树(请实现两个函数,分别用来序列化和反序列化二叉树)
/*1. 对于序列化:使用前序遍历,递归的将二叉树的值转化为字符,并且在每次二叉树的结点不为空时,在转化val所得的字符之后添加一个','作为分割。对于空节点则以 '#' 代替。
2. 对于反序列化:按照前序顺序,递归的使用字符串中的字符创建一个二叉树(特别注意:在递归时,递归函数的参数一定要是char ** ,这样才能保证每次递归后指向字符串的指针会随着递归的进行而移动!!!)*/
void Serialize(BinaryTreeNode* pRoot,ostream& stream)
{
if (pRoot == NULL)
{
stream << "$,";
return;
}
stream << pRoot->m_nValue<<',';
Serialize(pRoot->m_pLeft,stream);
Serialize(pRoot->m_pRight,stream);
}
void Deserialize(BinaryTreeNode** pRoot,istream& stream)
{
int number;
if (ReadStream(stream,&number))
{
*pRoot = new BinaryTreeNode();
(*pRoot)->m_pValue = number;
(*pRoot)->m_pLeft = NULL;
(*pRoot)->m_pRight = NULL;
Deserialize(&((*pRoot)->m_pLeft),stream);
Deserialize(&((*pRoot)->m_pRight),stream);
}
}
面试题63:二叉搜索树的第k个结点
TreeNode* KthNode(TreeNode* pRoot, unsigned int k)
{
if (pRoot == NULL || k <= 0) return NULL;
vector<TreeNode*> vec;
Inorder(pRoot, vec);
if (k>vec.size())
return NULL;
return vec[k - 1];
}
void Inorder(TreeNode* pRoot, vector<TreeNode*>& vec)
{
if (pRoot == NULL) return;
Inorder(pRoot->left, vec);
vec.push_back(pRoot);
Inorder(pRoot->right, vec);
}
面试题64:数据流中的中位数
查找 | 插入 | 删除 |
---|
数组 | O(n) | O(1) |
有序数组 | O(logn) | O(n) |
链表 | O(n) | O(1) |
有序链表 | O(n) | O(n) |
二叉树(一般情况) | O(logn) | O(logn) |
二叉树(最坏情况) | O(n) | O(n) |
平衡树 | O(logn) | O(logn) |
哈希表 | O(1) | O(1) |
class Solution_63
{
public:
void Insert(int num)
{
count += 1;
if (count % 2 == 0) {
big_heap.push(num);
small_heap.push(big_heap.top());
big_heap.pop();
}
else {
small_heap.push(num);
big_heap.push(small_heap.top());
small_heap.pop();
}
}
double GetMedian()
{
if (count & 0x1) {
return big_heap.top();
}
else {
return double((small_heap.top() + big_heap.top()) / 2.0);
}
}
private:
int count = 0;
priority_queue<int, vector<int>, less<int>> big_heap;
priority_queue<int, vector<int>, greater<int>> small_heap;
};
5.栈和队列
面试题65:滑动窗口的最大值
vector<int> maxInWindows(const vector<int>& num, unsigned int size)
{
vector<int> vec;
if (num.size() <= 0 || num.size()<size || size <= 0)
return vec;
deque<int> dq;
for (unsigned int i = 0;i<size;i++)
{
while (!dq.empty() && num[i] >= num[dq.back()])
dq.pop_back();
dq.push_back(i);
}
for (unsigned int i = size;i<num.size();i++)
{
vec.push_back(num[dq.front()]);
while (!dq.empty() && num[i] >= num[dq.back()])
dq.pop_back();
if (!dq.empty() && dq.front() <= (int)(i - size))
dq.pop_front();
dq.push_back(i);
}
vec.push_back(num[dq.front()]);
return vec;
}
6.回溯法
面试题66:矩阵中的路径(判断在一个矩阵中是否存在一条包含某字符串所有字符的路径)
bool hasPath(char* matrix,int rows,int cols,char* str)
{
if (matrix == NULL || rows<1 || cols <1 || str==NULL)
return false;
bool* visited = new bool[rows*cols];
memset(visited,0,rows*cols);
int pathLength = 0;
for (int row=s;row<rows;++row)
{
for (int col = 0;col<cols;++col)
{
if (hasPathCore(matrix,rows,cols,row,col,str,pathLength,visited))
return true;
}
}
delete[] visited;
return false;
}
bool hasPathCore(char* matrix,int rows,int cols,int row,int col,char* str,int pathLength,bool* visited)
{
if (str[pathLength] == '\0')
return true;
bool hasPath = false;
if (row>=0 && row<rows && col>=0 && col<cols && matrix[row*cols +col] == str[pathLength] && !visited[row*cols+col])
{
++pathLength;
visited[row*cols+col] = true;
haspath = hasPathCore(matrix,rows,cols,row,col-1,str,pathLength,visited)
|| hasPathCore(matrix,rows,cols,row-1,col,str,pathLength,visited)
|| hasPathCore(matrix,rows,cols,row,col+1,str,pathLength,visited)
|| hasPathCore(matrix,rows,cols,row+1,col,str,pathLength,visited);
if (!hasPath)
{
--pathLength;
visited[row*cols+col] = false;
}
}
return hasPath;
}
面试题67:机器人的运动范围
int movingCount(int threshold, int rows, int cols)
{
bool* flag = new bool[rows*cols];
for (int i = 0;i<rows*cols;i++)
flag[i] = false;
int count = moving(threshold, rows, cols, 0, 0, flag);
delete[] flag;
return count;
}
int moving(int threshold, int rows, int cols, int i, int j, bool* flag)
{
int count = 0;
if (check(threshold, rows, cols, i, j, flag)) {
flag[i*cols + j] = true;
count = 1 + moving(threshold, rows, cols, i - 1, j, flag)
+ moving(threshold, rows, cols, i, j - 1, flag)
+ moving(threshold, rows, cols, i + 1, j, flag)
+ moving(threshold, rows, cols, i, j + 1, flag);
}
return count;
}
bool check(int threshold, int rows, int cols, int i, int j, bool* flag)
{
if (i >= 0 && i<rows && j >= 0 && j<cols
&& getSum(i) + getSum(j) <= threshold
&& flag[i*cols + j] == false)
return true;
return false;
}
int getSum(int number)
{
int sum = 0;
while (number>0)
{
sum += number % 10;
number /= 10;
}
return sum;
}