用棧來(lái)求解漢諾塔問(wèn)題

題目

在漢諾塔規(guī)則的基礎(chǔ)上三椿,限制不能從最左的塔移動(dòng)到最右的塔上箩兽,必須經(jīng)過(guò)中間的塔绅项,移動(dòng)的跨度只能是一個(gè)塔。當(dāng)塔有N層的時(shí)候比肄,打印最優(yōu)移動(dòng)過(guò)程和最優(yōu)移動(dòng)步數(shù)。

要求

  • 方法一:使用遞歸的方法進(jìn)行移動(dòng)
  • 方法二:使用棧進(jìn)行移動(dòng)

解答思路

方法一:

無(wú)論多少層囊陡,都看作有兩層芳绩,最大的一層(命名為X)、(N-1)層合并起來(lái)的作為一層(命名為Y)撞反,目標(biāo)是將X移動(dòng)到最右側(cè)妥色,然后再把Y移動(dòng)到最右側(cè)。

漢諾塔
遞歸的移動(dòng)方式:
  • Y從A塔移動(dòng)到B塔
  • Y從B塔移動(dòng)到C塔
  • X從A塔移動(dòng)到B塔
  • Y從C塔移動(dòng)到B塔
  • Y從B塔移動(dòng)到A塔
  • X從B塔移動(dòng)到C塔
  • 將Y看做X遏片,繼續(xù)遞歸移動(dòng)
實(shí)現(xiàn)代碼:
import java.util.Stack;

/**
 * 每次移動(dòng)只能移動(dòng)一個(gè)柱子,不能跨柱子移動(dòng)
 * @author zhanyongzhi
 */
public class HannoiOneStep {
    public void startMove(int count){
        move(count, "A", "B", "C");
    }

    private void move(int item, String from, String buffer, String to){
        //
        if(1 == item){
            System.out.println(String.format("move %d from %s to %s", item, from, buffer));
            System.out.println(String.format("move %d from %s to %s", item, buffer, to));
            return;
        }

        //general situation
        move(item - 1, from, buffer, to);
        System.out.println(String.format("move %d from %s to %s", item, from, buffer));
        move(item - 1, to, buffer, from);
        System.out.println(String.format("move %d from %s to %s", item, buffer, to));

        move(item - 1, from, buffer, to);
    }
}

方法二:

使用棧而不使用遞歸的方式進(jìn)行移動(dòng)嘹害,使用3個(gè)棧模擬3個(gè)塔,每一步的移動(dòng)吮便,都按照真實(shí)情況進(jìn)行笔呀。
??按照規(guī)則,可能的移動(dòng)動(dòng)作限定為L(zhǎng)M髓需、ML许师、MR、RM四種步驟(L僚匆、M微渠、R分布表示左中右),通過(guò)引入逆反原則和小壓大原則咧擂,可以得出每次移動(dòng)逞盆,只有一種可行步驟。

逆反原則

當(dāng)執(zhí)行了LM松申,如果此時(shí)下一步執(zhí)行ML云芦,叫做逆反操作,這樣會(huì)使得漢諾塔還原為上一步的形狀攻臀,白走多一步焕数,這樣明顯不是最優(yōu)的方法,所以不能夠執(zhí)行逆反操作刨啸,叫逆反原則堡赔。

小壓大原則

當(dāng)移動(dòng)時(shí),小的塊總是在大塊之上设联,叫小壓大原則善已。

限制分析

當(dāng)上一步為:LM灼捂,下一步的情況分析:

  • 執(zhí)行LM,違反小壓大原則
  • 執(zhí)行ML换团,違反逆反原則
  • 執(zhí)行MR還是RM悉稠,按照小壓大原則,這兩種情況是互斥的艘包,只能按條件二選一

其他分析類(lèi)似的猛,省略...

實(shí)現(xiàn)代碼

package com.github.zhanyongzhi.interview.algorithm.stacklist;

import java.util.Stack;

/**
 * 使用棧模擬漢諾塔移動(dòng),將towerA全部層移動(dòng)到towerC
 * @author zhanyongzhi
 */
public class HannoiStack {
    private Stack<Integer> towerA = new Stack<>();
    private Stack<Integer> towerB = new Stack<>();
    private Stack<Integer> towerC = new Stack<>();

    private MoveType preMoveType = MoveType.LM;

    enum MoveType{
        LM("Move From Left to Middle"),
        MR("Move From Middle to Right"),
        RM("Move From Right to Middle"),
        ML("Move From Middle to Left");

        private final String name;

        MoveType(String s) {
            name = s;
        }

        public boolean equalsName(String otherName) {
            return (otherName == null) ? false : name.equals(otherName);
        }

        public String toString() {
            return name;
        }
    }

    public void init(int size){
        for(int i=size; 0 < i; i--){
            towerA.push(i);
        }
    }

    public void startMove(){
        int layerSize = towerA.size();

        while(layerSize != towerC.size()){
            moveStack(MoveType.LM, MoveType.ML, towerA, towerB);
            moveStack(MoveType.MR, MoveType.RM, towerB, towerC);
            moveStack(MoveType.RM, MoveType.MR, towerC, towerB);
            moveStack(MoveType.ML, MoveType.LM, towerB, towerA);
        }
    }

    private void moveStack(MoveType tryMove, MoveType preventMove, final Stack<Integer> towerFrom, final Stack<Integer> towerTo){
        if(preMoveType == preventMove)
            return;

        if(towerFrom.empty())
            return;

        Integer sElement = towerFrom.peek();

        if(!towerTo.empty()){
            Integer dElement = towerTo.peek();

            if(sElement > dElement)
                return;
        }

        preMoveType = tryMove;

        System.out.println(tryMove);
        towerFrom.pop();
        towerTo.push(sElement);
    }
}

在github中查看

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市想虎,隨后出現(xiàn)的幾起案子卦尊,更是在濱河造成了極大的恐慌,老刑警劉巖舌厨,帶你破解...
    沈念sama閱讀 222,252評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件岂却,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡裙椭,警方通過(guò)查閱死者的電腦和手機(jī)躏哩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)揉燃,“玉大人扫尺,你說(shuō)我怎么就攤上這事〈短溃” “怎么了器联?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,814評(píng)論 0 361
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)婿崭。 經(jīng)常有香客問(wèn)我拨拓,道長(zhǎng),這世上最難降的妖魔是什么氓栈? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,869評(píng)論 1 299
  • 正文 為了忘掉前任渣磷,我火速辦了婚禮,結(jié)果婚禮上授瘦,老公的妹妹穿的比我還像新娘醋界。我一直安慰自己,他們只是感情好提完,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,888評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布形纺。 她就那樣靜靜地躺著,像睡著了一般徒欣。 火紅的嫁衣襯著肌膚如雪逐样。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,475評(píng)論 1 312
  • 那天,我揣著相機(jī)與錄音脂新,去河邊找鬼挪捕。 笑死,一個(gè)胖子當(dāng)著我的面吹牛争便,可吹牛的內(nèi)容都是我干的级零。 我是一名探鬼主播,決...
    沈念sama閱讀 41,010評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼滞乙,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼奏纪!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起斩启,我...
    開(kāi)封第一講書(shū)人閱讀 39,924評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤亥贸,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后浇垦,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,469評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡荣挨,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,552評(píng)論 3 342
  • 正文 我和宋清朗相戀三年男韧,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片默垄。...
    茶點(diǎn)故事閱讀 40,680評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡此虑,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出口锭,到底是詐尸還是另有隱情朦前,我是刑警寧澤,帶...
    沈念sama閱讀 36,362評(píng)論 5 351
  • 正文 年R本政府宣布鹃操,位于F島的核電站韭寸,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏荆隘。R本人自食惡果不足惜恩伺,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,037評(píng)論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望椰拒。 院中可真熱鬧晶渠,春花似錦、人聲如沸燃观。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,519評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)缆毁。三九已至番川,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背爽彤。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,621評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工养盗, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人适篙。 一個(gè)月前我還...
    沈念sama閱讀 49,099評(píng)論 3 378
  • 正文 我出身青樓往核,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親嚷节。 傳聞我的和親對(duì)象是個(gè)殘疾皇子聂儒,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,691評(píng)論 2 361

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