數(shù)據(jù)結(jié)構(gòu)與算法題(持續(xù)更新...)

最近找工作看到了一篇數(shù)據(jù)結(jié)構(gòu)與算法題的結(jié)構(gòu)的面試題集合覺得還不錯(cuò)飒硅,正好這方面是自己的弱點(diǎn),正好現(xiàn)在開始補(bǔ)一補(bǔ)浸须。數(shù)據(jù)結(jié)構(gòu)與算法面試題80道

下面從第一題開始一道一道開始擼

1.把二元查找樹轉(zhuǎn)變成排序的雙向鏈表

題目:
輸入一棵二元查找樹移怯,將該二元查找樹轉(zhuǎn)換成一個(gè)排序的雙向鏈表。
要求不能創(chuàng)建任何新的結(jié)點(diǎn)和橙,只調(diào)整指針的指向仔燕。

   10
 / \
 6 14
 / \ / \
4 8 12 16

轉(zhuǎn)換成雙向鏈表
4=6=8=10=12=14=16。
首先我們定義的二元查找樹 節(jié)點(diǎn)的數(shù)據(jù)結(jié)構(gòu)如下:

 struct BSTreeNode
{
 int m_nValue; // value of node
 BSTreeNode *m_pLeft; // left child of node
 BSTreeNode *m_pRight; // right child of node
};

據(jù)說這是微軟面試題魔招,像這種有關(guān)樹的題基本上都需要用到遞歸算法
解題思路:我們可以中序遍歷整棵樹晰搀。按照這個(gè)方式遍歷樹,比較小的結(jié)點(diǎn)先訪問办斑。如果我們每訪問一個(gè)結(jié)點(diǎn)外恕,假設(shè)之前訪問過的結(jié)點(diǎn)已經(jīng)調(diào)整成一個(gè)排序雙向鏈表,我們?cè)侔颜{(diào)整當(dāng)前結(jié)點(diǎn)的指針將其鏈接到鏈表的末尾。當(dāng)所有結(jié)點(diǎn)都訪問過之后吁讨,整棵樹也就轉(zhuǎn)換成一個(gè)排序雙向鏈表了髓迎。

///////////////////////////////////////////////////////////////////////
// Covert a sub binary-search-tree into a sorted double-linked list
// Input: pNode -           the head of the sub tree
//        pLastNodeInList - the tail of the double-linked list
///////////////////////////////////////////////////////////////////////
void ConvertNode(BSTreeNode* pNode, BSTreeNode*& pLastNodeInList)
{
      if(pNode == NULL)
            return;
    //   獲取當(dāng)前的節(jié)點(diǎn)
      BSTreeNode *pCurrent = pNode;

      // Convert the left sub-tree
    //   如果有做節(jié)點(diǎn)就遞歸遍歷左節(jié)點(diǎn)
      if (pCurrent->m_pLeft != NULL)
            ConvertNode(pCurrent->m_pLeft, pLastNodeInList);

      // Put the current node into the double-linked list
    //   如果沒有左節(jié)點(diǎn)就把已經(jīng)排序好的鏈表放到當(dāng)前節(jié)點(diǎn)的左節(jié)點(diǎn)
    // 通俗的說就是把當(dāng)前節(jié)點(diǎn)排到鏈表的末尾
      pCurrent->m_pLeft = pLastNodeInList; 
      if(pLastNodeInList != NULL)
            pLastNodeInList->m_pRight = pCurrent;//雙向鏈表要把右節(jié)點(diǎn)也填上
    // 把指針挪到了鏈表的未結(jié)點(diǎn)
      pLastNodeInList = pCurrent;

      // Convert the right sub-tree
      //如果右節(jié)點(diǎn)的話接著遞歸進(jìn)行中序遍歷
      if (pCurrent->m_pRight != NULL)
            ConvertNode(pCurrent->m_pRight, pLastNodeInList);
}

///////////////////////////////////////////////////////////////////////
// Covert a binary search tree into a sorted double-linked list
// Input: pHeadOfTree - the head of tree
// Output: the head of sorted double-linked list
///////////////////////////////////////////////////////////////////////
BSTreeNode* Convert_Solution1(BSTreeNode* pHeadOfTree)
{
    //初始化一個(gè)空的鏈表 作為結(jié)果
      BSTreeNode *pLastNodeInList = NULL;
      ConvertNode(pHeadOfTree, pLastNodeInList);

      // Get the head of the double-linked list
      BSTreeNode *pHeadOfList = pLastNodeInList;
      while(pHeadOfList && pHeadOfList->m_pLeft)
            pHeadOfList = pHeadOfList->m_pLeft;

      return pHeadOfList;
}

具體的已經(jīng)寫注釋啦 遞歸的特點(diǎn)就是代碼簡(jiǎn)單,但是理解起來(lái)比較復(fù)雜

2.定義棧的數(shù)據(jù)結(jié)構(gòu)建丧, 要求添加一個(gè) min 函數(shù)排龄, 能夠得到棧的最小元素。 要求函數(shù) min翎朱、 push 以及 pop 的時(shí)間復(fù)雜度都是 O(1)

剛開始解這道題目的時(shí)候橄维,感覺不是很難,只需在棧的數(shù)據(jù)結(jié)構(gòu)中加一個(gè)選項(xiàng)min就OK了拴曲,這樣就可以記錄最小值争舞。但是這個(gè)思路有一個(gè)硬傷,那就是第一次調(diào)用min函數(shù)時(shí)澈灼,是可以直接獲取到最小值竞川,但是如果調(diào)用pop()函數(shù)將最小值出棧過后,再給min賦值時(shí)叁熔,就需要進(jìn)行查找比較了委乌,那樣就不滿足題目要求,min函數(shù)的復(fù)雜度為1. 既然如此荣回,那我們是否可以記錄下每push進(jìn)一個(gè)數(shù)據(jù)時(shí)當(dāng)前的min值遭贸,每一次發(fā)生變化就將當(dāng)前的min值壓入到一個(gè)數(shù)組中,這樣就可以解決上述問題心软。因此這道題目的難點(diǎn)我認(rèn)為就是數(shù)組設(shè)計(jì)是否合理壕吹。
設(shè)計(jì)了以下的數(shù)組結(jié)構(gòu):
源程序如下:

#include<iostream>
using namespace std;

#define MAXSIZE 100

typedef int ElemType;

struct Stack{
    int top;//當(dāng)前棧頂位置
    int index;//當(dāng)前最小min位置
    ElemType data[MAXSIZE];//存儲(chǔ)棧的數(shù)據(jù)
    ElemType minData[MAXSIZE];//存儲(chǔ)最小值的合集
    int min;//記錄最小值(預(yù)留)
};

//初始化棧
bool InitStack(Stack* ptr){
    ptr->top = 0;
    ptr->index = 0;
    ptr->min = 0;

    return true;
}

bool push(Stack* ptr, ElemType elem){
    //首先需要判斷棧是否已滿
    if(MAXSIZE-1 == ptr->top){
        cout << "Stack is full, cannot push data anymore!" << endl;
        return false;
    }
    //判斷是否是第一個(gè)壓入棧的數(shù)據(jù),將最小值存儲(chǔ)到minStack中
    if(0 == ptr->top){
        // 第一個(gè)數(shù)據(jù)直接賦值成最小值
        ptr->min = elem;
        // 注意此處是后++  計(jì)算完再++
        ptr->minData[ptr->index++] = elem;
    } else if(elem <= ptr->min){//如果入棧的數(shù)據(jù)比當(dāng)前最小值小
        ptr->min = elem;
        // 最小值如果更改了就把更改狀態(tài)的值存進(jìn)去,里面的數(shù)值可能是重復(fù)的
        ptr->minData[ptr->index++] = ptr->min;
    }
    // 把值存到數(shù)據(jù)的棧的數(shù)組中
    ptr->data[(ptr->top)++] = elem;

    return true;
}

ElemType pop(Stack* ptr, ElemType* elem){
    //判斷棧是否為空
    if(0 == ptr->top){
        cout << "stack is empty, cannot pop data anymore!" << endl;
        return -65535;
    }
    // 因?yàn)閜ush的時(shí)候已經(jīng)進(jìn)行了后++ 删铃,所以此處想獲取當(dāng)前的位置就先--
    *elem = ptr->data[--(ptr->top)];

    int i = ptr->index - 1;
    if(*elem == ptr->minData[i]){
        --(ptr->index);
    }

    return *elem;
}

ElemType minMethod(Stack* ptr){
    // 此處維護(hù)了一個(gè)數(shù)組耳贬,所以時(shí)間復(fù)雜度為1
    return ptr->minData[--(ptr->index)];
}
// data 5,4,4,4
// min  5,4,4,4

int main() {
    Stack ptr;
    int elem;
    // 初始化棧
    InitStack(&ptr);
    push(&ptr, 5);
    push(&ptr, 4);
    push(&ptr, 4);
    push(&ptr, 4);
//  cout << "pop1: " << pop(&ptr, &elem) << endl;
//  push(&ptr, 8);
    pop(&ptr, &elem);
    pop(&ptr, &elem);
    pop(&ptr, &elem);
//  cout << "pop2: " << pop(&ptr, &elem) << endl;
    cout << "minMethod: " << minMethod(&ptr) << endl;

    return 0;
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市泳姐,隨后出現(xiàn)的幾起案子效拭,更是在濱河造成了極大的恐慌,老刑警劉巖胖秒,帶你破解...
    沈念sama閱讀 221,695評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件缎患,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡阎肝,警方通過查閱死者的電腦和手機(jī)挤渔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)风题,“玉大人判导,你說我怎么就攤上這事嫉父。” “怎么了眼刃?”我有些...
    開封第一講書人閱讀 168,130評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵绕辖,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我擂红,道長(zhǎng)仪际,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,648評(píng)論 1 297
  • 正文 為了忘掉前任昵骤,我火速辦了婚禮树碱,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘变秦。我一直安慰自己成榜,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,655評(píng)論 6 397
  • 文/花漫 我一把揭開白布蹦玫。 她就那樣靜靜地躺著赎婚,像睡著了一般。 火紅的嫁衣襯著肌膚如雪钳垮。 梳的紋絲不亂的頭發(fā)上惑淳,一...
    開封第一講書人閱讀 52,268評(píng)論 1 309
  • 那天额港,我揣著相機(jī)與錄音饺窿,去河邊找鬼。 笑死移斩,一個(gè)胖子當(dāng)著我的面吹牛肚医,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播向瓷,決...
    沈念sama閱讀 40,835評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼肠套,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了猖任?” 一聲冷哼從身側(cè)響起你稚,我...
    開封第一講書人閱讀 39,740評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎朱躺,沒想到半個(gè)月后刁赖,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,286評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡长搀,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,375評(píng)論 3 340
  • 正文 我和宋清朗相戀三年宇弛,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片源请。...
    茶點(diǎn)故事閱讀 40,505評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡枪芒,死狀恐怖彻况,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情舅踪,我是刑警寧澤纽甘,帶...
    沈念sama閱讀 36,185評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站抽碌,受9級(jí)特大地震影響贷腕,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜咬展,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,873評(píng)論 3 333
  • 文/蒙蒙 一泽裳、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧破婆,春花似錦涮总、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,357評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至裳扯,卻和暖如春抛丽,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背饰豺。 一陣腳步聲響...
    開封第一講書人閱讀 33,466評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工亿鲜, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人冤吨。 一個(gè)月前我還...
    沈念sama閱讀 48,921評(píng)論 3 376
  • 正文 我出身青樓蒿柳,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親漩蟆。 傳聞我的和親對(duì)象是個(gè)殘疾皇子垒探,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,515評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容