剑指Offer-第2章 面试需要的基础知识

面试题1: 赋值运算符函数

clip_image002

一般的写法是如下形式:

 

CMyString& operator=(const CMyString& str){
            if(this!=&str){
                delete[] m_pData;
                int sz=strlen(str.m_pData);
                m_pData=new char[sz+1];
                strcpy(m_pData,str.m_pData);
            }
            return *this;
        }

clip_image004

CMyString& operator=(const CMyString& str){
            if(this!=&str){
                CMyString tmp_str(str);
                char *p=m_pData;
                m_pData=tmp_str.m_pData;
                tmp_str.m_pData=p;
            }
            return *this;
        }

完整的测试实例如下:

class CMyString{
    public:
        CMyString(char *pData=NULL){
            if(pData==NULL){
                m_pData=new char[1];
                m_pData[0]='\0';
            }
            else{
                int sz=strlen(pData);
                m_pData=new char[sz+1];
                strcpy(m_pData,pData);
            }
        }
        CMyString(const CMyString& str){
            int sz=strlen(str.m_pData);
            m_pData=new char[sz+1];
            strcpy(m_pData,str.m_pData);
        }
        ~CMyString(){
            delete[] m_pData;
        }
        //经典写法,适用于初级程序员
        /*
        CMyString& operator=(const CMyString& str){
            if(this!=&str){
                delete[] m_pData;
                int sz=strlen(str.m_pData);
                m_pData=new char[sz+1];
                strcpy(m_pData,str.m_pData);
            }
            return *this;
        }
         */
        //考虑异常安全性,高级写法
        CMyString& operator=(const CMyString& str){
            if(this!=&str){
                CMyString tmp_str(str);
                char *p=m_pData;
                m_pData=tmp_str.m_pData;
                tmp_str.m_pData=p;
            }
            return *this;
        }
        void print(ostream& os)const {
            os<<m_pData;
        }
    private:
        char* m_pData;
};
       ostream& operator<<(ostream& os,const CMyString& str){
           str.print(os);
            return os;
        }
void Test1()
{
    printf("Test1 begins:\n");

    char* text = "Hello world";

    CMyString str1(text);
    CMyString str2;
    str2 = str1;

    printf("The expected result is: %s.\n", text);

    printf("The actual result is: ");
    cout<<str2<<endl;
}

// 赋值给自己
void Test2()
{
    printf("Test2 begins:\n");

    char* text = "Hello world";

    CMyString str1(text);
    str1 = str1;

    printf("The expected result is: %s.\n", text);

    printf("The actual result is: ");
    cout<<str1<<endl;
}

// 连续赋值
void Test3()
{
    printf("Test3 begins:\n");

    char* text = "Hello world";

    CMyString str1(text);
    CMyString str2, str3;
    str3 = str2 = str1;

    printf("The expected result is: %s.\n", text);

    printf("The actual result is: ");
    cout<<str2<<endl;

    printf("The expected result is: %s.\n", text);

    printf("The actual result is: ");
    cout<<str3<<endl;
}

int main()
{
    Test1();
    Test2();
    Test3();

    return 0;
}

面试题2: 实现singleton模式

clip_image006

//这是基本的形式
class singleton_{
    public:
        static singleton_* get_instance(){
            if(_instance==0)
                _instance=new singleton_;
            return _instance;
        }
    private:
        singleton_(){}
        ~singleton_(){}
        static singleton_* _instance;
};
singleton_* singleton_::_instance=0;

//下面的方法可以应用在多线程中,主要是利用锁的帮助
class locker{
    public:
        locker(){
            pthread_mutex_init(&mutex,NULL);
        }
        ~locker(){
            pthread_mutex_destroy(&mutex);
        }
        void lock(){
            pthread_mutex_lock(&mutex);
        }
        void unlock(){
            pthread_mutex_unlock(&mutex);
        }
    private:
        pthread_mutex_t mutex;
};
class singleton{
    public:
        static singleton* get_instance();
    private:
        singleton(){}
        ~singleton(){}
    private:
        static singleton* _instance;
        static locker llock;
};
singleton* singleton::_instance=0;
locker singleton::llock;
singleton* singleton::get_instance(){
    if(_instance==0){
        llock.lock();
        printf("locked\n");
        if(_instance==0)
            _instance=new singleton;
        llock.unlock();
        printf("unlocked\n");
    }
    return _instance;
}
int main(){
    int pid;
    for(int i=0;i<2;i++){
        pid=fork();
        if(pid<0)
            printf("error\n");
        else if(pid==0){
            singleton* slt=singleton::get_instance();
            printf("child:%x\n",slt);
        }
        else{
            singleton* slt=singleton::get_instance();
            printf("parent:%x\n",slt);
        }

    }

}

参考: http://blog.csdn.net/joanlynnlove/article/details/7462254

面试题3: 二维数组中的查找

clip_image008

clip_image010

代码如下:

bool FindInPartiallySortedMatrix(int *matrix,int row,int col,int number){
    if(matrix==0||row<0||col<0)
        return false;
    int i=0,j=col-1;
    while(i<row&&j>=0){
        int t=matrix[i*col+j];
        if(t==number)
            return true;
        else if(t>number)
            --j;
        else
            i++;
    }
    return false;
}
// ====================测试代码====================
void Test(char* testName, int* matrix, int rows, int columns, int number, bool expected)
{
    if(testName != NULL)
        printf("%s begins: ", testName);

    bool result = FindInPartiallySortedMatrix(matrix, rows, columns, number);
    if(result == expected)
        printf("Passed.\n");
    else
        printf("Failed.\n");
}

//  1   2   8   9
//  2   4   9   12
//  4   7   10  13
//  6   8   11  15
// 要查找的数在数组中
void Test1()
{
    int matrix[][4] = {{1, 2, 8, 9}, {2, 4, 9, 12}, {4, 7, 10, 13}, {6, 8, 11, 15}};
    Test("Test1", (int*)matrix, 4, 4, 7, true);
}

//  1   2   8   9
//  2   4   9   12
//  4   7   10  13
//  6   8   11  15
// 要查找的数不在数组中
void Test2()
{
    int matrix[][4] = {{1, 2, 8, 9}, {2, 4, 9, 12}, {4, 7, 10, 13}, {6, 8, 11, 15}};
    Test("Test2", (int*)matrix, 4, 4, 5, false);
}

//  1   2   8   9
//  2   4   9   12
//  4   7   10  13
//  6   8   11  15
// 要查找的数是数组中最小的数字
void Test3()
{
    int matrix[][4] = {{1, 2, 8, 9}, {2, 4, 9, 12}, {4, 7, 10, 13}, {6, 8, 11, 15}};
    Test("Test3", (int*)matrix, 4, 4, 1, true);
}

//  1   2   8   9
//  2   4   9   12
//  4   7   10  13
//  6   8   11  15
// 要查找的数是数组中最大的数字
void Test4()
{
    int matrix[][4] = {{1, 2, 8, 9}, {2, 4, 9, 12}, {4, 7, 10, 13}, {6, 8, 11, 15}};
    Test("Test4", (int*)matrix, 4, 4, 15, true);
}

//  1   2   8   9
//  2   4   9   12
//  4   7   10  13
//  6   8   11  15
// 要查找的数比数组中最小的数字还小
void Test5()
{
    int matrix[][4] = {{1, 2, 8, 9}, {2, 4, 9, 12}, {4, 7, 10, 13}, {6, 8, 11, 15}};
    Test("Test5", (int*)matrix, 4, 4, 0, false);
}

//  1   2   8   9
//  2   4   9   12
//  4   7   10  13
//  6   8   11  15
// 要查找的数比数组中最大的数字还大
void Test6()
{
    int matrix[][4] = {{1, 2, 8, 9}, {2, 4, 9, 12}, {4, 7, 10, 13}, {6, 8, 11, 15}};
    Test("Test6", (int*)matrix, 4, 4, 16, false);
}

// 鲁棒性测试,输入空指针
void Test7()
{
    Test("Test7", NULL, 0, 0, 16, false);
}

int main(int argc, char* argv[])
{
    Test1();
    Test2();
    Test3();
    Test4();
    Test5();
    Test6();
    Test7();

    return 0;
}

面试题4: 替换空格

clip_image012

这儿的关键问题是替换后字符串的长度变大了, 所以主要的问题是如何在低复杂度情况下完成复制.

代码如下:

void replace_blank(char *str,int capacity){
    if(str==0||capacity<0)
        return ;
    int blk_cnt=0;
    int len=0;
    while(str[len]!='\0') {
        if(str[len]==' ')
            blk_cnt++;
        len++;
    }
    if(len+1+blk_cnt*2>capacity)
        return ;
    char *p1,*p2;
    p1=str+len+1;
    p2=str+len+1+blk_cnt*2;
    while(p1>=str&&p2>=p1){
        if(*p1==' '){
            p1--;
            *p2--='0';
            *p2--='2';
            *p2--='%';
        }
        else
            *p2--=*p1--;
    }

}
void Test(char* testName, char string[], int length, char expected[])
{
    if(testName != NULL)
        printf("%s begins: ", testName);

    replace_blank(string, length);

    if(expected == NULL && string == NULL)
        printf("passed.\n");
    else if(expected == NULL && string != NULL)
        printf("failed.\n");
    else if(strcmp(string, expected) == 0)
        printf("passed.\n");
    else
        printf("failed.\n");
}

// 空格在句子中间
void Test1()
{
    const int length = 100;

    char string[length] = "hello world";
    Test("Test1", string, length, "hello%20world");
}

// 空格在句子开头
void Test2()
{
    const int length = 100;

    char string[length] = " helloworld";
    Test("Test2", string, length, "%20helloworld");
}

// 空格在句子末尾
void Test3()
{
    const int length = 100;

    char string[length] = "helloworld ";
    Test("Test3", string, length, "helloworld%20");
}

// 连续有两个空格
void Test4()
{
    const int length = 100;

    char string[length] = "hello  world";
    Test("Test4", string, length, "hello%20%20world");
}

// 传入NULL
void Test5()
{
    Test("Test5", NULL, 0, NULL);
}

// 传入内容为空的字符串
void Test6()
{
    const int length = 100;

    char string[length] = "";
    Test("Test6", string, length, "");
}

//传入内容为一个空格的字符串
void Test7()
{
    const int length = 100;

    char string[length] = " ";
    Test("Test7", string, length, "%20");
}

// 传入的字符串没有空格
void Test8()
{
    const int length = 100;

    char string[length] = "helloworld";
    Test("Test8", string, length, "helloworld");
}

// 传入的字符串全是空格
void Test9()
{
    const int length = 100;

    char string[length] = "   ";
    Test("Test9", string, length, "%20%20%20");
}

int main(int argc, char* argv[])
{
    Test1();
    Test2();
    Test3();
    Test4();
    Test5();
    Test6();
    Test7();
    Test8();
    Test9();

    return 0;
}

面试题5: 从尾到头打印链表

clip_image014

本题目中需要用到链表的定义:

struct ListNode{
    int m_nValue;
    ListNode* m_pNext;
};
ListNode* CreateListNode(int value)
{
    ListNode* pNode = new ListNode();
    pNode->m_nValue = value;
    pNode->m_pNext = NULL;

    return pNode;
}

void ConnectListNodes(ListNode* pCurrent, ListNode* pNext)
{
    if(pCurrent == NULL)
    {
        printf("Error to connect two nodes.\n");
        exit(1);
    }

    pCurrent->m_pNext = pNext;
}

void PrintListNode(ListNode* pNode)
{ 
    if(pNode == NULL)
    {
        printf("The node is NULL\n");
    }
    else
    {
        printf("The key in node is %d.\n", pNode->m_nValue);
    }
}

void PrintList(ListNode* pHead)
{
    printf("PrintList starts.\n");
    
    ListNode* pNode = pHead;
    while(pNode != NULL)
    {
        printf("%d\t", pNode->m_nValue);
        pNode = pNode->m_pNext;
    }

    printf("\nPrintList ends.\n");
}

void DestroyList(ListNode* pHead)
{
    ListNode* pNode = pHead;
    while(pNode != NULL)
    {
        pHead = pHead->m_pNext;
        delete pNode;
        pNode = pHead;
    }
}

void AddToTail(ListNode** pHead, int value)
{
    ListNode* pNew = new ListNode();
    pNew->m_nValue = value;
    pNew->m_pNext = NULL;

    if(*pHead == NULL)
    {
        *pHead = pNew;
    }
    else
    {
        ListNode* pNode = *pHead;
        while(pNode->m_pNext != NULL)
            pNode = pNode->m_pNext;

        pNode->m_pNext = pNew;
    }
}

void RemoveNode(ListNode** pHead, int value)
{
    if(pHead == NULL || *pHead == NULL)
        return;

    ListNode* pToBeDeleted = NULL;
    if((*pHead)->m_nValue == value)
    {
        pToBeDeleted = *pHead;
        *pHead = (*pHead)->m_pNext;
    }
    else
    {
        ListNode* pNode = *pHead;
        while(pNode->m_pNext != NULL && pNode->m_pNext->m_nValue != value)
            pNode = pNode->m_pNext;

        if(pNode->m_pNext != NULL && pNode->m_pNext->m_nValue == value)
        {
            pToBeDeleted = pNode->m_pNext;
            pNode->m_pNext = pNode->m_pNext->m_pNext;
        }
    }

    if(pToBeDeleted != NULL)
    {
        delete pToBeDeleted;
        pToBeDeleted = NULL;
    }
}

本题的代码如下:

void PrintListReversingly_Iteratively(ListNode* pHead){
    if(pHead==0)
        return ;
    stack<ListNode*> st;
    ListNode* p=pHead;
    while(p!=0){
        st.push(p);
        p=p->m_pNext;
    }
    while(!st.empty()){
        p=st.top();st.pop();
        cout<<p->m_nValue<<' ';
    }
    cout<<endl;
}
void PrintListReversingly_Recursively(ListNode* pHead){
    if(pHead==0)
        return;
    PrintListReversingly_Recursively(pHead->m_pNext);
    cout<<pHead->m_nValue<<' ';
}
void Test(ListNode* pHead)
{
    PrintList(pHead);
    PrintListReversingly_Iteratively(pHead);
    printf("\n");
    PrintListReversingly_Recursively(pHead);
}

// 1->2->3->4->5
void Test1()
{
    printf("\nTest1 begins.\n");

    ListNode* pNode1 = CreateListNode(1);
    ListNode* pNode2 = CreateListNode(2);
    ListNode* pNode3 = CreateListNode(3);
    ListNode* pNode4 = CreateListNode(4);
    ListNode* pNode5 = CreateListNode(5);

    ConnectListNodes(pNode1, pNode2);
    ConnectListNodes(pNode2, pNode3);
    ConnectListNodes(pNode3, pNode4);
    ConnectListNodes(pNode4, pNode5);

    Test(pNode1);

    DestroyList(pNode1);
}

// 只有一个结点的链表: 1
void Test2()
{
    printf("\nTest2 begins.\n");

    ListNode* pNode1 = CreateListNode(1);

    Test(pNode1);

    DestroyList(pNode1);
}

// 空链表
void Test3()
{
    printf("\nTest3 begins.\n");

    Test(NULL);
}

int main(int argc, char* argv[])
{
    Test1();
    Test2();
    Test3();

    return 0;
}

面试题6: 重建二叉树

clip_image016

二叉树相关的定义:

struct BinaryTreeNode 
{
    int                    m_nValue; 
    BinaryTreeNode*        m_pLeft;  
    BinaryTreeNode*        m_pRight; 
};
BinaryTreeNode* CreateBinaryTreeNode(int value)
{
    BinaryTreeNode* pNode = new BinaryTreeNode();
    pNode->m_nValue = value;
    pNode->m_pLeft = NULL;
    pNode->m_pRight = NULL;

    return pNode;
}

void ConnectTreeNodes(BinaryTreeNode* pParent, BinaryTreeNode* pLeft, BinaryTreeNode* pRight)
{
    if(pParent != NULL)
    {
        pParent->m_pLeft = pLeft;
        pParent->m_pRight = pRight;
    }
}

void PrintTreeNode(BinaryTreeNode* pNode)
{
    if(pNode != NULL)
    {
        printf("value of this node is: %d\n", pNode->m_nValue);

        if(pNode->m_pLeft != NULL)
            printf("value of its left child is: %d.\n", pNode->m_pLeft->m_nValue);
        else
            printf("left child is null.\n");

        if(pNode->m_pRight != NULL)
            printf("value of its right child is: %d.\n", pNode->m_pRight->m_nValue);
        else
            printf("right child is null.\n");
    }
    else
    {
        printf("this node is null.\n");
    }

    printf("\n");
}

void PrintTree(BinaryTreeNode* pRoot)
{
    PrintTreeNode(pRoot);

    if(pRoot != NULL)
    {
        if(pRoot->m_pLeft != NULL)
            PrintTree(pRoot->m_pLeft);

        if(pRoot->m_pRight != NULL)
            PrintTree(pRoot->m_pRight);
    }
}

void DestroyTree(BinaryTreeNode* pRoot)
{
    if(pRoot != NULL)
    {
        BinaryTreeNode* pLeft = pRoot->m_pLeft;
        BinaryTreeNode* pRight = pRoot->m_pRight;

        delete pRoot;
        pRoot = NULL;

        DestroyTree(pLeft);
        DestroyTree(pRight);
    }
}

本题的代码如下:

BinaryTreeNode* ConstructCore(int* startPreorder, int* endPreorder, int* startInorder, int* endInorder);

BinaryTreeNode* Construct(int* preorder, int* inorder, int length){
    if(preorder==0||inorder==0||length<0)
        return 0;
    return ConstructCore(preorder,preorder+length-1,inorder,inorder+length-1);
}
BinaryTreeNode* ConstructCore(int* startPreorder, int* endPreorder, int* startInorder, int* endInorder){
    //判断输入是否合法
    if(startPreorder>endPreorder||startInorder>endInorder)
        return 0;
    int rootValue=startPreorder[0];
    BinaryTreeNode* root=new BinaryTreeNode;
    root->m_nValue=rootValue;
    root->m_pLeft=root->m_pRight=0;
    if(startPreorder==endPreorder){
        if(startInorder==endInorder&&*startPreorder==*startInorder)
        return root;
        else
            throw exception();

    }
    int *rootInorder=startInorder;
    while(rootInorder<=endInorder&&*rootInorder!=rootValue)
        ++rootInorder;
    if(rootInorder>endInorder||rootInorder==endInorder&&*rootInorder!=rootValue)
            throw std::exception();
    int len=rootInorder-startInorder;
    //对len的检查和开头的判断检查的效果是一样的。
//    if(len>0)
    root->m_pLeft=ConstructCore(startPreorder+1,startPreorder+len,startInorder,rootInorder-1);
//    if(len<endPreorder-startPreorder)
    root->m_pRight=ConstructCore(startPreorder+len+1,endPreorder,rootInorder+1,endInorder);
    return root;
}
// ====================测试代码====================
void Test(char* testName, int* preorder, int* inorder, int length)
{
    if(testName != NULL)
        printf("%s begins:\n", testName);

    printf("The preorder sequence is: ");
    for(int i = 0; i < length; ++ i)
        printf("%d ", preorder[i]);
    printf("\n");

    printf("The inorder sequence is: ");
    for(int i = 0; i < length; ++ i)
        printf("%d ", inorder[i]);
    printf("\n");

    try
    {
        BinaryTreeNode* root = Construct(preorder, inorder, length);
        PrintTree(root);

        DestroyTree(root);
    }
    catch(std::exception& exception)
    {
        printf("Invalid Input.\n");
    }
}

// 普通二叉树
//              1
//           /     \
//          2       3  
//         /       / \
//        4       5   6
//         \         /
//          7       8
void Test1()
{
    const int length = 8;
    int preorder[length] = {1, 2, 4, 7, 3, 5, 6, 8};
    int inorder[length] = {4, 7, 2, 1, 5, 3, 8, 6};

    Test("Test1", preorder, inorder, length);
}

// 所有结点都没有右子结点
//            1
//           / 
//          2   
//         / 
//        3 
//       /
//      4
//     /
//    5
void Test2()
{
    const int length = 5;
    int preorder[length] = {1, 2, 3, 4, 5};
    int inorder[length] = {5, 4, 3, 2, 1};

    Test("Test2", preorder, inorder, length);
}

// 所有结点都没有左子结点
//            1
//             \ 
//              2   
//               \ 
//                3 
//                 \
//                  4
//                   \
//                    5
void Test3()
{
    const int length = 5;
    int preorder[length] = {1, 2, 3, 4, 5};
    int inorder[length] = {1, 2, 3, 4, 5};

    Test("Test3", preorder, inorder, length);
}

// 树中只有一个结点
void Test4()
{
    const int length = 1;
    int preorder[length] = {1};
    int inorder[length] = {1};

    Test("Test4", preorder, inorder, length);
}

// 完全二叉树
//              1
//           /     \
//          2       3  
//         / \     / \
//        4   5   6   7
void Test5()
{
    const int length = 7;
    int preorder[length] = {1, 2, 4, 5, 3, 6, 7};
    int inorder[length] = {4, 2, 5, 1, 6, 3, 7};

    Test("Test5", preorder, inorder, length);
}

// 输入空指针
void Test6()
{
    Test("Test6", NULL, NULL, 0);
}

// 输入的两个序列不匹配
void Test7()
{
    const int length = 7;
    int preorder[length] = {1, 2, 4, 5, 3, 6, 7};
    int inorder[length] = {4, 2, 8, 1, 6, 3, 7};

    Test("Test7: for unmatched input", preorder, inorder, length);
}

int main(int argc, char* argv[])
{
    Test1();
    Test2();
    Test3();
    Test4();
    Test5();
    Test6();
    Test7();

    return 0;
}

面试题7: 用两个栈实现队列操作

clip_image018

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> CQueue<T>::CQueue(void)
{
}

template <typename T> CQueue<T>::~CQueue(void)
{
}

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 exception();

    T head = stack2.top();
    stack2.pop();

    return head;
}
void Test(char actual, char expected)
{
    if(actual == expected)
        printf("Test passed.\n");
    else
        printf("Test failed.\n");
}

int main(int argc, char* argv[])
{
    CQueue<char> queue;

    queue.appendTail('a');
    queue.appendTail('b');
    queue.appendTail('c');

    char head = queue.deleteHead();
    Test(head, 'a');

    head = queue.deleteHead();
    Test(head, 'b');

    queue.appendTail('d');
    head = queue.deleteHead();
    Test(head, 'c');

    queue.appendTail('e');
    head = queue.deleteHead();
    Test(head, 'd');

    head = queue.deleteHead();
    Test(head, 'e');

    return 0;
}

面试题8: 旋转数组的最小数字

clip_image020

很多题目会用到快排的思想, 快排中最核心的地方就是利用一个数将数组分为两部分, 实现方法如下:

方法1: 从两边往中间遍历

int Partition(int *a,int low,int high){
    if(a== NULL || low>high)
        throw new std::exception();
    int pivot=a[low];
    int i=low,j=high+1;
    while(1){
        do
            i++;
        while(a[i]<pivot);
        do
            j--;
        while(a[j]>pivot);
        if(i>=j)
            break;
        swap(a[i],a[j]);
    }
    swap(a[low],a[j]);
    return j;
}

方法2: 从一边往另一边遍历,比较巧

int RandomInRange(int minl,int maxl){
    return rand()%(maxl-minl+1)+minl;
}

int Partition_(int data[],int start, int end)
{
    if(data == NULL || start >end )
        throw new std::exception();

    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)
                swap(data[index], data[small]);
        }
    }

    ++ small;
    swap(data[small], data[end]);

    return small;
}

clip_image022

代码如下:

int MinInOrder(int* numbers, int index1, int index2);
int Min(int *arr,int len){
    if(arr==0||len<=0)
        throw exception();
    int i=0,j=len-1;
    int mid=i;
    while(arr[i]>=arr[j]){
        //如果前后指针指向相邻的两个数,那么后面的那个数就是我们所要查找的。
        if(j-i==1){
            mid=j;
            break;
        }
        mid=(i+j)/2;
        //如果三个数相同,只能采取线性查找了。
        if(arr[i]==arr[j]&&
                arr[mid]==arr[i])
            return MinInOrder(arr,i,j);
        //缩小查找范围
        if(arr[mid]>=arr[i])
            i=mid;
       else if(arr[mid]<=arr[j])
            j=mid;
    }
    return arr[mid];
}
//线性查找
int MinInOrder(int *a,int l,int r){
    int res=a[l];
    for(int i=l;i<r;i++)
        if(res>a[i])
            res=a[i];
    return res;
}
// ====================测试代码====================
void Test(int* numbers, int length, int expected)
{
    int result = 0;
    try
    {
        result = Min(numbers, length);

        for(int i = 0; i < length; ++i)
            printf("%d ", numbers[i]);

        if(result == expected)
            printf("\tpassed\n");
        else
            printf("\tfailed\n");
    }
    catch (...)
    {
        if(numbers == NULL)
            printf("Test passed.\n");
        else
            printf("Test failed.\n");
    }
}

int main(int argc, char* argv[])
{
    // 典型输入,单调升序的数组的一个旋转
    int array1[] = {3, 4, 5, 1, 2};
    Test(array1, sizeof(array1) / sizeof(int), 1);

    // 有重复数字,并且重复的数字刚好的最小的数字
    int array2[] = {3, 4, 5, 1, 1, 2};
    Test(array2, sizeof(array2) / sizeof(int), 1);

    // 有重复数字,但重复的数字不是第一个数字和最后一个数字
    int array3[] = {3, 4, 5, 1, 2, 2};
    Test(array3, sizeof(array3) / sizeof(int), 1);

    // 有重复的数字,并且重复的数字刚好是第一个数字和最后一个数字
    int array4[] = {1, 0, 1, 1, 1};
    Test(array4, sizeof(array4) / sizeof(int), 0);

    // 单调升序数组,旋转0个元素,也就是单调升序数组本身
    int array5[] = {1, 2, 3, 4, 5};
    Test(array5, sizeof(array5) / sizeof(int), 1);

    // 数组中只有一个数字
    int array6[] = {2};
    Test(array6, sizeof(array6) / sizeof(int), 2);

    // 输入NULL
    Test(NULL, 0, 0);

    return 0;
}

面试题9: 斐波那契数列

clip_image024

这儿总结一下所有求解斐波那契数列的方法:

方法1:

经典的递归方式.

方法2:

迭代的方式

方法3:

比较巧的方法, 根据递推表达式得到一个矩阵的表示形式:

clip_image025

三种方法的代码如下:

int Fibonacci1(int n){
    if(n==0)
        return 0;
    if(n==1)
        return 1;
    return Fibonacci1(n-1)+Fibonacci1(n-2);
}
int Fibonacci2(int n){
    if(n==0)
        return 0;
    if(n==1)
        return 1;
    int fn,fn_1,fn_2;
    fn_1=1,fn_2=0;
    for(int i=2;i<=n;i++){
        fn=fn_1+fn_2;
        fn_2=fn_1;
        fn_1=fn;
    }
    return fn;
}
struct Matrix2By2
{
    Matrix2By2
    (
        long long m00 = 0, 
        long long m01 = 0, 
        long long m10 = 0, 
        long long m11 = 0
    )
    :m_00(m00), m_01(m01), m_10(m10), m_11(m11) 
    {
    }

    long long m_00;
    long long m_01;
    long long m_10;
    long long m_11;
};

Matrix2By2 MatrixMultiply
(
    const Matrix2By2& matrix1, 
    const Matrix2By2& matrix2
)
{
    return Matrix2By2(
        matrix1.m_00 * matrix2.m_00 + matrix1.m_01 * matrix2.m_10,
        matrix1.m_00 * matrix2.m_01 + matrix1.m_01 * matrix2.m_11,
        matrix1.m_10 * matrix2.m_00 + matrix1.m_11 * matrix2.m_10,
        matrix1.m_10 * matrix2.m_01 + matrix1.m_11 * matrix2.m_11);
}

Matrix2By2 MatrixPower(unsigned int n)
{
    assert(n > 0);

    Matrix2By2 matrix;
    if(n == 1)
    {
        matrix = Matrix2By2(1, 1, 1, 0);
    }
    else if(n % 2 == 0)
    {
        matrix = MatrixPower(n / 2);
        matrix = MatrixMultiply(matrix, matrix);
    }
    else if(n % 2 == 1)
    {
        matrix = MatrixPower((n - 1) / 2);
        matrix = MatrixMultiply(matrix, matrix);
        matrix = MatrixMultiply(matrix, Matrix2By2(1, 1, 1, 0));
    }

    return matrix;
}

long long Fibonacci3(unsigned int n)
{
    int result[2] = {0, 1};
    if(n < 2)
        return result[n];

    Matrix2By2 PowerNMinus2 = MatrixPower(n - 1);
    return PowerNMinus2.m_00;
}

// ====================测试代码====================
void Test(int n, int expected)
{
    if(Fibonacci1(n) == expected)
        printf("Test for %d in solution1 passed.\n", n);
    else
        printf("Test for %d in solution1 failed.\n", n);

    if(Fibonacci2(n) == expected)
        printf("Test for %d in solution2 passed.\n", n);
    else
        printf("Test for %d in solution2 failed.\n", n);

    if(Fibonacci3(n) == expected)
        printf("Test for %d in solution3 passed.\n", n);
    else
        printf("Test for %d in solution3 failed.\n", n);
}

int main(int argc, char* argv[])
{
    Test(0, 0);
    Test(1, 1);
    Test(2, 1);
    Test(3, 2);
    Test(4, 3);
    Test(5, 5);
    Test(6, 8);
    Test(7, 13);
    Test(8, 21);
    Test(9, 34);
    Test(10, 55);

    Test(40, 102334155);

    return 0;
}

clip_image027

clip_image029

clip_image031

面试题10: 二进制中1的个数

clip_image033

很多的解法.

方法1:

不断的除以2或右移. 判断其中1的个数.

存在的问题是, 对于负数就不行了.

方法2:

将1不断左移, 然后与原数进行按位与操作.

方法3:

利用n&(n-1)的技巧

方法2和3的代码如下:

int NumberOf1_Solution1(int n)
{
    int count = 0;
    unsigned int flag = 1;
    while(flag)
    {
        if(n & flag)
            count ++;

        flag = flag << 1;
    }

    return count;
}

int NumberOf1_Solution2(int n)
{
    int count = 0;

    while (n)
    {
        ++ count;
        n = (n - 1) & n;
    }

    return count;
}

void Test(int number, unsigned int expected)
{
    int actual = NumberOf1_Solution1(number);
    if(actual == expected)
        printf("Solution1: Test for %p passed.\n", number);
    else
        printf("Solution1: Test for %p failed.\n", number);

    actual = NumberOf1_Solution2(number);
    if(actual == expected)
        printf("Solution2: Test for %p passed.\n", number);
    else
        printf("Solution2: Test for %p failed.\n", number);

    printf("\n");
}

int main(int argc, char* argv[])
{
    // 输入0,期待的输出是0
    Test(0, 0);

    // 输入1,期待的输出是1
    Test(1, 1);

    // 输入10,期待的输出是2
    Test(10, 2);

    // 输入0x7FFFFFFF,期待的输出是31
    Test(0x7FFFFFFF, 31);

    // 输入0xFFFFFFFF(负数),期待的输出是32
    Test(0xFFFFFFFF, 32);

    // 输入0x80000000(负数),期待的输出是1
    Test(0x80000000, 1);

    return 0;
}

clip_image035clip_image037

posted @ 2012-11-07 08:47  Mr.Rico  阅读(313)  评论(0编辑  收藏  举报