algorithm 題集八 (18.03.25)

本文一共12題,均來自《劍指offer》,不復雜。在平時的練習中收集了部分組合而成。

(1)輸入某二叉樹的前序遍歷和中序遍歷的結果,請重建出該二叉樹。假設輸入的前序遍歷和中序遍歷的結果中都不含重複的數字。例如輸入前序遍歷序列{1,2,4,7,3,5,6,8}和中序遍歷序列{4,7,2,1,5,3,8,6},則重建二叉樹並返回。

(2)用兩個棧來實現一個隊列,完成隊列的Push和Pop操作。隊列中的元素爲int類型。

(3)用兩個隊列實現一個棧。完成棧的Push,Pop,top等操作。

(4)把一個數組最開始的若干個元素搬到數組的末尾,我們稱之爲數組的旋轉。輸入一個非遞減排序的數組的一個旋轉,輸出旋轉數組的最小元素。例如數組{3,4,5,1,2}爲{1,2,3,4,5}的一個旋轉,該數組的最小值爲1。NOTE:給出的所有元素都大於0,若數組大小爲0,請返回0。

(5)大家都知道斐波那契數列,現在要求輸入一個整數n,請你輸出斐波那契數列的第n項。n<=39。(斐波那契數列:1、1、2、3、5、8、13、21、34、…… 在數學上,斐波納契數列以如下被以遞歸的方法定義:F(0)=0,F(1)=1, F(n)=F(n-1)+F(n-2))

(6)一隻青蛙一次可以跳上1級臺階,也可以跳上2級。求該青蛙跳上一個n級的臺階總共有多少種跳法。

(7)一隻青蛙一次可以跳上1級臺階,也可以跳上2級……它也可以跳上n級。求該青蛙跳上一個n級的臺階總共有多少種跳法。

(8)鏈表反轉。

(9)輸入兩個單調遞增的鏈表,輸出兩個鏈表合成後的鏈表,當然我們需要合成後的鏈表滿足單調不減規則。

(10)輸入兩棵二叉樹A,B,判斷B是不是A的子結構。(ps:我們約定空樹不是任意一個樹的子結構)

(11)輸入一個矩陣,按照從外向裏以順時針的順序依次打印出每一個數字,例如,如果輸入如下矩陣: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 則依次打印出數字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10.

(12)定義棧的數據結構,請在該類型中實現一個能夠得到棧最小元素的min函數。


思路:
(1)遞歸查找頂點。
(2)一個棧專門負責進,另一個棧專門負責出。
(3)一個隊列負責主存儲,另一個隊列負責臨時存儲(用於輔助實現pop操作)。
(4)第一種思路:暴力,直接從後面向前遍歷,直到找到最小值。第二種思路:由於原始數組是非遞減數組,那麼旋轉後的數組後面第二部分的任意一個元素一定是小於等於前面任何一個元素。然後,我們可以使用二分不斷縮小比較的空間。
思路二的大致過程:
先確定left = 0, right = size -1。二分得到mid = (left+right)>>1
如果array[mid] > array[left], 那麼array[mid]屬於第一部分,left = mid
如果array[mid] < array[left],那麼array[mid]屬於第二部分,right = mid
如果array[mid] == array[left],那麼有可能是3 1 3 3 3,也有可能是 3 3 3 1 3。兩種情況均滿足條件。故無法判斷,直接暴力搜索。
(5)個人覺得,最快的方法是在構造函數中打表,然後解答函數直接輸出array[n]。
(6)動態規劃問題,當青蛙跳到第n級,可供選擇的路徑共有F(n-1) + F[n-2]。所以遞推式就是菲波那切數列。
(7)尋找規律:

f[1] = 1
f[2] = f[1]+1 = 2
f[3] = f[1]+f[2]+1 = 4
f[4] = f[1]+f[2]+f[3]+1 = 8
f[5] = f[1]+f[2]+f[3]+f[4]+1 = 16
==> f[n] = 2^(n-1)

(8)放兩個指針記錄遍歷指針的前節點和後節點。然後改變遍歷指針的next指向。一趟遍歷完整就完成了任務。

    ListNode* ReverseList(ListNode* pHead) {
        ListNode* next = NULL;
        ListNode* pre = NULL;
        while(pHead){
            next = pHead->next;
            pHead->next = pre;
            pre = pHead;
            pHead = next;
        }
        return pre;
    }

(9)將麻煩事交給計算機,我們指出關鍵步驟即可。遞歸無敵!

class Solution {
public:
    ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
    {
        if(pHead1 == NULL) return pHead2;
        else if(pHead2 == NULL) return pHead1;
        else {
            if(pHead1->val <= pHead2->val){
                pHead1->next = Merge(pHead1->next,pHead2);
                return pHead1;
            }
            else {
                pHead2->next = Merge(pHead1,pHead2->next);
                return pHead2;
            }
        }
    }
};

(10)首先需要確定滿足“相同(子結構)”
然後左右子樹遞歸查找。

/*
struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
    TreeNode(int x) :
            val(x), left(NULL), right(NULL) {
    }
};*/
class Solution {
public:
    bool isSubtree(TreeNode* pRoot1, TreeNode* pRoot2) {
        if(pRoot2 == NULL) return true;
        if(pRoot1 == NULL) return false;
        if(pRoot1->val == pRoot2->val){
            return isSubtree(pRoot1->left, pRoot2->left) && isSubtree(pRoot1->right, pRoot2->right);
        }
        else  return false;
    }
    bool HasSubtree(TreeNode* pRoot1, TreeNode* pRoot2)
    {
        if(pRoot1 == NULL || pRoot2 == NULL) return false;
        return isSubtree(pRoot1, pRoot2) || \
                HasSubtree(pRoot1->left,pRoot2) || \
                HasSubtree(pRoot1->right,pRoot2); 
    }
};

(11)我的方案:找到需要打印的圈數和左上頂點,打印外圍數字。這樣由外向內循環下去。
然後,看到其他網友的解法。有一個非常的巧妙:打印第一行,然後刪除此行,接着逆時針旋轉90度構造新的矩形。重新這個步驟。

(12)添加一個輔助棧,用於每次push元素壓入新的最小元素,每次pop元素彈出棧頂元素,min函數直接查詢輔助棧的棧頂元素即可。
當然,我沒想那麼多(呵呵),直接去暴力實現了。

class Solution {
    int *data;
    unsigned int length;
    unsigned int size;

public:
    Solution(){
        length = 0;
        size = 0;
        data = NULL;
    }
    ~Solution(){
        length = 0;
        size = 0;
        delete data;
        data = NULL;
    }
    unsigned int _align_it(unsigned int newSize){
        return newSize+(sizeof(int)-1) & ~(sizeof(int)-1);
    }
    unsigned int recommend(unsigned int newSize){
        return std::max(2*length, _align_it(newSize));
    }
    void reserve(unsigned int size){
        if(size > length) {
            int old_length = length;
            int *old_data = data;
            length = recommend(size);
            data = new int[length];
            for(int i=0; i<old_length; i++){
                data[i] = old_data[i];
            }
            delete old_data;
        }
    }
    void push(int value) {
        reserve(++size);
        data[size-1] = value;
    }
    void pop() {
        if(size == 0){
            return ;
        }
        size--;
    }
    int top() {
        try{
            if(size == 0) throw "there is no number in data.";
            return data[size-1];
        }
        catch(char *str){
            cout<<str<<endl;
            return -1;
        }
    }
    int min() {
        try{
            if(length == 0) throw "length is equal to zero";
            int minVal = data[0];
            for(int i=1;i<size;i++){
                minVal = minVal<data[i]?minVal:data[i];
            }
            return minVal;
        }
        catch(char *str){
            cout<<str<<endl;
            return -1;
        }
    }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章