面試題38:數字在排序數組中出現的次數
題目:統計一個數字在排序數組中出現的次數。例如輸入排序數組{1,2,3,3,3,3,4,5}和數字3,由於3在這個數組中出現了4次,因此輸出4。
//遞歸的代碼找到排列數組中的第一個k:
int GetFirstK(int* data,int length,int k,int start,int end)
{
if(start > end)
return -1;
int middleIndex = (start + end) / 2;
int middleData = data[middleIndex];
if(middleData == k)
{
if((middleIndex > 0 && data[middleIndex - 1] != k)
|| middleIndex == 0)
return middleIndex;
else
end = middleIndex - 1;
}
else if(middleData > k)
end = middleIndex - 1;
else
start = middleIndex + 1;
return GetFirstK(data,length,k,start,end);
}
int GetLastK(int* data,int length,int k,int start,int end)
{
if(start > end)
return -1;
int middleIndex = (start + end) / 2;
int middleData = data[middleIndex];
if(middleData == k)
{
if((middleIndex < length - 1 && data[middleIndex +1 ] != k)
|| middleIndex == length - 1)
{
return middleIndex;
}
else
start = middleIndex + 1;
}
else if(middleData < k)
start =middleIndex + 1;
else
end = middleIndex - 1;
return GetLastK(data,length,k,start,end);
}
//在分別找到第一個k和最後一個k的下標之後,我們就能計算出k在數組中出現的次數了。
int GetNumberOfK(int* data,int length, int k)
{
int number = 0;
if(data != NULL && length > 0)
{
int first = GetFirstK(data,length,k,0,length -1);
int last = GetLastK(data,length,k,0,length - 1);
if(first > -1 && last > -1)
number = last - first +1;
}
return number;
}
在上述代碼中,GetFirstK和GetLastK都是用二叉查找法在數組中查找一個合乎要求的數字,它們的時間複雜度都是O(logn),因此GetNumberOfK的總的時間複雜度也只有O(logn)。
面試題39:二叉樹的深度
題目一:輸入一棵二叉樹的根結點,求該樹的深度。從根結點到葉結點依次經過的結點(含根、葉結點)形成樹的一條路徑,最長路徑的長度爲樹的深度。
二叉樹的結點定義如下:
struct BinaryTreeNode
{
int m_nValue;
BinaryTreeNode* m_pLeft;
BinaryTreeNode* m_pRight;
};
用遞歸的方式實現代碼如下:
int TreeDepth(BinaryTreeNode* pRoot)
{
if(pRoot == NULL)
return 0;
int nLeft = TreeDepth(pRoot->m_pLeft);
int nRight = TreeDepth(pRoot->m_pRight);
return (nLeft > nRight) ? (nLeft + 1):(nRight + 1);
}
題目二:輸入一棵二叉樹的根結點,判斷該樹是不是平衡二叉樹。如果某二叉樹中任意結點的左右子樹的深度相差不超過1,那麼它就是一棵平衡二叉樹。
方法一:調用函數TreeDepth得到它的左右子樹的深度。如果每個結點的左右子樹的深度相差都不超過1,按照定義它就是一棵平衡的二叉樹。代碼如下:
bool IsBalanced(BinaryTreeNode* pRoot)
{
if(pRoot == NULL)
return true;
int left = TreeDepth(pRoot->m_pLeft);
int right = TreeDepth(pRoot->m_pRight);
int diff = left - right;
if(diff > 1 || diff < -1)
return false;
return IsBalanced(pRoot->m_pLeft) && IsBalanced(pRoot->m_pRight);
}
上面的代碼固然簡潔,但我們也要注意到由於一個結點會被重複遍歷多次,這種思路的時間效率不高。
每個結點只遍歷一次的解法,正是面試官喜歡的
bool IsBalanced(BinaryTreeNode* pRoot,int* pDepth)
{
if(pRoot == NULL)
{
*pDepth = 0;
return true;
}
int left,right;
if(IsBalanced(pRoot->m_pLeft,&left)
&& IsBalanced(pRoot->m_pRight,&right))
{
int diff = left - right;
if(diff <= 1 && diff >= -1)
{
*pDepth = 1 + (left > right ? left :right);
return true;
}
}
return false;
}
bool IsBalanced(BinaryTreeNode* pRoot)
{
int depth = 0;
return IsBalanced(pRoot,&depth);
}
在上面的代碼中,我們用後序遍歷的方式遍歷整棵二叉樹。在遍歷某結點的左右子結點之後,我們可以根據它的左右子結點的深度判斷它是不是平衡的,並得到當前結點的深度。當最後遍歷到樹的根結點的時候,也就判斷整棵二叉樹是不是平衡二叉樹。
參考資料《劍指Offer》