【劍指Offer】俯視50題之1-10題
面試題1賦值運算符函數?
面試題2 實現Singleton模式?
面試題3 二維數組中的查找
?
面試題4 替換空格
?
面試題5 從頭到尾打印鏈表
?
面試題6 重建二叉樹
?
面試題7 用兩個棧實現隊列
?
面試題8 旋轉數組的最小數字?
面試題9 斐波那契數列
?
面試題9(變形) 跳臺階
?
面試題9(變形) 變態跳臺階?
面試題9(變形) 矩形覆蓋
?
面試題10 二進制中1的個數?
面試題1賦值運算符函數?
為以下類型加入賦值運算符
答案例如以下:class CMyString { public: CMyString(char *pData = NULL); CMyString(const CMyString &str); ~CMyString(void); private: char *m_pData; };
CMyString& CMyString::operator==(const CMyString &str) { char *temp; if (&str==this)/*指針推斷*/ { return *this;/*返回應用*/ } temp= (char *)malloc(strlen(this->m_pData)+1); strncpy(temp, this->m_pData, strlen(this->m_pData)); if (m_pData != NULL) { free(m_pData); m_pData = NULL; } m_pData = (char *)malloc(strlen(str.m_pData)+1); if (m_pData == NULL) { strncpy(this->m_pData,temp,strlen(temp)); return *this; } strncpy(this->m_pData, str.m_pData, strlen(str.m_pData)); return *this; }
註意:
? ? ? ? ?1. 返回值是類型的引用 CMyString& ,使得能夠連續賦值 str1 = str2 =str3
? ? ? ? ?2. 穿入參數是常量引用,假設是實例則會多出一個從形參到實參構造函數。
? ? ? ? ?3. 是否釋放了自身內存,否則會出現內存泄露。
? ? ? ? ?4. 必須推斷是否是自身實例,否則內存釋放之後,會出現空指針訪問
? ? ? ? ?5. 申請內存是否推斷申請成功,註意保存先前值,在沒有申請成功的
面試題2 實現Singleton模式
答案例如以下:
單線程模式下的單利模式
class Singleton { public: static Singleton* GetInstance(void) { if (m_instance == NULL) { m_instance = new Singleton(); } return m_instance; } private: Singleton(); static Singleton *m_instance; };
說明:程序退出時會自己主動析構靜態變量和全局變量
多線程模式下的單利模式
class Singleton
{
public:
static Singleton* GetInstance(void)
{
if (m_instance == NULL)
{
lockBase* lockbase = new lockBase();
lockBase->lock();
if (m_instance == NULL)
{
m_instance = new Singleton();
}
lockBase->unlock();
}
return m_instance;
}
private:
Singleton();
static Singleton *m_instance;
};
class lockBase{
protected:
friend class singleStance;
CRITICAL_SECTION cs;
public :
lockBase(){
::InitializeCriticalSection(&cs);
}
void lock(){
::EnterCriticalSection(&cs);
}
void unlock(){
::LeaveCriticalSection(&cs);
}
~lockBase(){
::DeleteCriticalSection(&cs);
}
};
面試題3 二維數組中的查找
? ? ? ? ? ? ? ?在一個二維數組中,每一行都是從左到右遞增,每一列都是從上到下遞增。給定一個二維數組。推斷一個數是否在這個二維數組中。
比如 7在以下的數組中?
?1,2。3
?4,5,6
?7,8,9?
答案例如以下:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define VOS_ERR 1
#define VOS_OK 0
int IsHaveValue(int str[][4],int a, int b, int value)
{
int i = 0;
int j = b - 1;
while(i<a && j >= 0)/* 還沒有到達左下角*/
{
if (str[i][j] == value)
{
return VOS_OK;
}
else if (str[i][j] > value)/* 大於要查找的數 ,去列 */
{
j--;
}
else
{
i++;
}
}
return VOS_ERR;
}
int main()
{
int str[][4] = { {1, 2, 8, 9},
{2, 4, 9,12},
{4, 7, 10, 13},
{6, 8, 11, 15}};
printf("%d\n",IsHaveValue(str,4,4,7));
printf("%d\n",IsHaveValue(str,4,4,26));
getchar();
}
註意:
1、簡單粗暴的方式就是遍歷,這樣的顯而易見的方式絕對不是面試官想要的。
? ? ? ? ?2、從右上角開始查找,大於要查找的數。則該列都不是想要的。刪除該列(列以下都大於要查找數)
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?小於要查找的數,則該行都不是想要的,刪除該行(行曾經都小於要查找數)
? 相等則返回OK
面試題4 替換空格?
? ? ? ? ? ? ? ? 實現一個函數,輸入一個字符串,將字符串中的空格替換成%20。
比如輸入"we are happy"替換成"we%20are%20happy"
實現例如以下:? ? ? ? ?
#include <iostream>
#define VOS_OK 0
#define VOS_ERR 1
char *ReplaceBank(char * str)
{
int strLen = 0;
int iBankNum = 0;
int iTotalNUm = 0;
char *strResult = NULL;
char *strTemp =NULL;
strLen = strlen(str);
for (int i=0; i<strLen; i++)
{
if (str[i] == ‘ ‘)
{
iBankNum++;
}
}
iTotalNUm = strLen + 2*iBankNum + 1;
strResult = (char*)malloc(iTotalNUm);
if (strResult == NULL)
{
return NULL;
}
strTemp = strResult;
for (int i = 0; i<iTotalNUm; i++)
{
if (str[i] == ‘ ‘)
{
*strTemp++ = ‘%‘;
*strTemp++ = ‘2‘;
*strTemp++ = ‘0‘;
}
else
{
*strTemp++ = str[i];
}
}
return strResult;
}
int main()
{
printf("%s\n",ReplaceBank("we are happy"));
getchar();
return VOS_OK;
}
註意:
1、空格*2 + 原來的長度是最後的長度。
2、假設傳入的是一個數組,則要復制成的長度要與原來的進行比較,假設大於數組長度則返回錯誤。
同類題目:
? ? ? ? 1、有兩個排序的數組A、B。當中A中有空間容納下B,實現一種方法將B插入到A中,並排序。
? ? ? ?思路:從A、B的尾部進行比較,將大的插入到合適的位置
面試題5 從尾到頭打印鏈表,輸入一個鏈表的頭指針,從尾部到頭輸出該鏈表。
思路:
假設同意改變鏈表結構,則將鏈表指針翻轉。即先前的頭部變成了尾部,尾部變成了頭部。然後順序順序輸出該鏈表。
? ? ? ? 假設不同意改變鏈表結構。則將順序讀鏈表,並依次放入棧中,等讀完鏈表之後。將棧中元素依次出棧則得到結果。
實現例如以下:
void PrintListReverse(Node *pHead)
{
stack<Node*> m_stack;
Node *pNode = pHead;
while(pNode != NULL)
{
m_stack.push(pNode);
pNode++;
}
while(!m_stack.empty())
{
pNode = m_stack.top();
printf("%s",pNode->data);
m_stack.pop();
}
}
? ? 使用棧來實現的還有一種變形為遞歸:
void PrintListReverse(Node *pHead)
{
if (pHead == NULL)
return;
if (pHead->next != NULL)
PrintListReverse(pHead->next);
printf("%s",pHead->data);
}
面試題6 重建二叉樹?
輸入二叉樹的前序遍歷和中序遍歷結果,輸出該樹。比如輸入前序遍歷結果為:1、2、4、7、3、5、6、8。
中序遍歷結果為:4、7、2、1、5、3、8、6
BinaryTreeNode *Construct(int *preOrder,int *inOrder,int length)
{
if (preOrder == NULL || preOrder == NULL || length <= 0)
{
return NULL;
}
BinaryTreeNode * root = ConstructCore(preOrder,preOrder + length - 1, inOrder,inOrder + length - 1);
}
BinaryTreeNode *ConstructCore(int *preOrderStart, int *preOrderEnd,
int *inOrderStart, int *inOrderEnd)
{
/*參數在調用處保證*/
BinaryTreeNode * root;
int inOrderleftLength = 0;
int *inOrderLocal;
root = (BinaryTreeNode *)malloc(sizeof(BinaryTreeNode));
if (root == NULL)
{
return NULL;
}
root->data = *preOrderStart;
root->lchild = root->rchild = NULL;
if (preOrderStart == preOrderEnd)
{
if (inOrderStart == inOrderEnd && *perOrderStart == *inOrderStart)
{
return root;
}
throws exception;
}
inOrderLocal = inOrderStart;
while(inOrderLocal++ != inOrderEnd)
{
if(*inOrderLocal != *preOrderStart)
{
inOrderleftLength++;
}
break;
}
root->lchild = ConstructCore(preOrderStart+1,preOrderStart+inOrderleftLength,inOrderStart,inOrderStart+inOrderleftLength);
root->rchild = ConstructCore(preOrderStart+inOrderleftLength+1,preOrderEnd, inOrderStart+inOrderleftLength+1,inOrderEnd);
return root;
}
註意:
1、利用遞歸的方法求解。註意入參。
面試題7 用兩個棧實現隊列
template <typename T>
class CQueue
{
public:
CQueue();
~CQueue();
void appendTail(const T &node);
T deleteHead();
private:
stack<T> stack1;
stack<T> stack2;
};
void CQueue::appendTail(const T & node)
{
stack1.push(node);
}
T CQueue::deleteHead()
{
T data;
if (!stack2.empty())
{
data = stack2.top();
stack2.pop();
return data;
}
while (!stack1.empty())
{
data = stack1.top();
stack2.push(data);
stack1.pop();
}
if (!stack2.empty())
{
data = stack2.top();
stack2.pop();
return data;
}
throw exception;
}
同類題目:
使用兩個隊列。實現一個棧。
實現例如以下:
class CStack
{
public:
CStack();
~CStack();
void pop();
void push();
private:
queue<T> queue1;
queue<T> queue2;
};
void CStack::push()
{
queue1.push();
}
void CStack::pop()
{
T data;
while (queue1.size()>1)
{
data = queue1.front();
queue2.push(data);
queue1.pop();
}
if (queue1.size()== 1)
{
queue1.pop();
return;
}
if (queue1.size()== 0)
{
if (queue2.size() == 0)
{
return;
}
while (queue2.size()>1)
{
data = queue2.front();
queue1.push(data);
queue2.pop();
}
if (queue2.size() == 1)
{
queue2.pop();
}
}
}
面試題8 旋轉數組的最小數字?
#include <iostream>
int GetMinValueException(int a[],int beginIndex, int endIndex)
{
int minValue;
if (beginIndex >= endIndex)
return a[beginIndex];
minValue = a[beginIndex];
for (int i = beginIndex + 1; i<=endIndex; i++)
{
if (a[i] < minValue)
minValue = a[i];
}
return minValue;
}
int GetMinValue(int a[],int beginIndex, int endIndex)
{
int midIndex = (beginIndex + endIndex)>>1;
if (beginIndex == endIndex)
{
return a[midIndex];
}
if (a[beginIndex] < a[endIndex])
{
return a[beginIndex];
}
if (a[midIndex] > a[beginIndex])
{
if (a[midIndex] > a[endIndex])
{
return GetMinValue(a,midIndex + 1, endIndex);
}
else
{
return GetMinValue(a,beginIndex,midIndex - 1);
}
}
if (a[midIndex] < a[beginIndex])
{
return GetMinValue(a,beginIndex,midIndex);
}
return GetMinValueException(a,beginIndex, endIndex);
}
int main()
{
int a[]={3,4,5,1,2};
int b[]={4,5,1,2,3};
int c[]={5,1,2,3,4};
int d[]={1,2,3,4,5};
int e[]={0,0,-1,0,0};
printf("%d\n",GetMinValue(a,0, 4));
printf("%d\n",GetMinValue(b,0, 4));
printf("%d\n",GetMinValue(c,0, 4));
printf("%d\n",GetMinValue(d,0, 4));
printf("%d\n",GetMinValue(e,0, 4));
}
面試題9 斐波那契數列,寫一個函數,輸入n,輸出斐波那契的第n個元素。
答案例如以下:
#include <iostream>
int Fibonacci(int n)
{
if (n == 0 || n == 1)
return n;
return Fibonacci(n-1) + Fibonacci(n-2);
}
int FibonacciSimple(int n)
{
int iIndex = 0;
int a1 = 0;
int a2 = 1;
int Result;
if (n == 0 || n == 1)
return n;
int *sArray = (int *)malloc(n);
for (iIndex = 2; iIndex <= n; iIndex++)
{
Result = a1 + a2;
a1 = a2;
a2 = Result;
}
return Result;
}
int main()
{
printf("%d\n",Fibonacci(10));
printf("%d\n",FibonacciSimple(10));
getchar();
}
說明:方法一採用遞歸,效率較低。方法二採用循環,先將結果存儲起來。再利用已經得到的結果求解,效率得到大幅度提升。
面試題9(變形) 跳臺階,青蛙一次能夠跳上1階。能夠跳上2階,也能夠跳到n階。問跳到n階總共同擁有多少種跳法?
?Fib(n) = Fib(n-1)+Fib(n-2)+Fib(n-3)+..........+Fib(n-n)
= Fib(0)+Fib(1)+Fib(2)+.......+Fib(n-1)
? ? ? 又由於Fib(n-1)=Fib(0)+Fib(1)+Fib(2)+.......+Fib(n-2)
? ? ? 兩式相減得:Fib(n)-Fib(n-1)=Fib(n-1) ? ? ? ? =====》 ?Fib(n) = 2*Fib(n-1) ? ? n >= 2
歸納總結為 2^(n-1)?
面試題10 二進制中1的個數?。輸入一個數。輸出該數的二進制表示中,1的個數。比如9表示為1001 共同擁有2個1
實現一:1挨個移位。挨個推斷是否為1
#include <iostream>
int GetOneNum(int n)
{
int num = 0;
int i = 1;
for (i = 0;i<32;i++)
{
if (n&(1<<i))
{
num++;
}
}
return num;
}
int main()
{
printf("%d\n",GetOneNum(9));
getchar();
}
實現二:僅僅推斷1的個數
int GetOneNum(int n)
{
int num = 0;
while(n)
{
num++;
n= (n -1) & n;
}
return num;
}
【劍指Offer】俯視50題之1-10題