算法練習(xí)(75): 斐波那契搜索(1.4.22)

本系列博客習(xí)題來(lái)自《算法(第四版)》悦析,算是本人的讀書(shū)筆記,如果有人在讀這本書(shū)的司光,歡迎大家多多交流琅坡。為了方便討論,本人新建了一個(gè)微信群(算法交流)残家,想要加入的榆俺,請(qǐng)?zhí)砑游业奈⑿盘?hào):zhujinhui207407 謝謝。另外坞淮,本人的個(gè)人博客 http://www.kyson.cn 也在不停的更新中茴晋,歡迎一起討論

算法(第4版)

知識(shí)點(diǎn)

  • 僅用加減實(shí)現(xiàn)的二分查找(斐波那契搜索)
  • 斐波那契數(shù)列的使用

題目

1.4.22 僅用加減實(shí)現(xiàn)的二分查找(Mihai Patrascu)。編寫(xiě)一個(gè)程序碾盐,給定一個(gè)含有 N 個(gè)不同 int 值的按照升序排列的數(shù)組晃跺,判斷它是否含有給定的整數(shù)揩局。只能使用加法和減法以及常數(shù)的額外內(nèi)存空間毫玖。程序的運(yùn)行時(shí)間在最壞情況下應(yīng)該和 logN 成正比。提示:用斐波那契數(shù)代替2的冪(二分法)進(jìn)行查找凌盯。用兩個(gè)變量保存Fk和Fk-1并在[i,i+Fk]之間查找付枫。在每一步中,使用減法計(jì)算Fk-2驰怎,檢查i+Fk-2處的元素阐滩,并根據(jù)結(jié)果將搜索范圍變?yōu)閇i,i+Fk-2]或是[i+Fk-2,i+Fk-2+Fk-1]。


1.4.22 Binary search with only addition and subtraction. [Mihai Patrascu] Write a program that, given an array of N distinct int values in ascending order, determines whether a given integer is in the array. You may use only additions and subtractions and a constant amount of extra memory. The running time of your program should be proportional to log N in the worst case.
Answer: Instead of searching based on powers of two (binary search), use Fibonacci numbers (which also grow exponentially). Maintain the current search range to be the interval [i, i + F k] and keep F k and F k–1 in two variables. At each step compute Fk–2 via subtraction, check element i + Fk–2 , and update the current range to either [i, i + Fk–2] or[i+Fk–2,i+Fk–2 +Fk–1].

分析

我們看題目中有個(gè)人名Mihai Patrascu县忌,這個(gè)人是誰(shuí)呢掂榔,我們先看一下知乎里的高票回答:
有哪些人堪稱「神人」,卻不為大眾所知症杏?

里面說(shuō)到:

算法界的天才人物Mihai P?tra?cu 于2012年P(guān)resburger獎(jiǎng)(青年理論計(jì)算科學(xué)頂級(jí)獎(jiǎng))装获,在數(shù)據(jù)結(jié)構(gòu)下限等基礎(chǔ)領(lǐng)域有突破貢獻(xiàn)。信息學(xué)奧林匹克IOI界的名人厉颤,獲得兩次金牌穴豫,一次銀牌。MIT博士逼友,師從神童教授Erik Demaine(沒(méi)讀中小學(xué)12歲上大學(xué)精肃,4年本科秤涩,1年master,1年phd司抱,20歲時(shí)博士畢業(yè))

他在麻省的介紹:http://people.csail.mit.edu/mip/
維基百科的介紹:https://en.wikipedia.org/wiki/Mihai_P%C4%83tra%C8%99cu

所以這個(gè)僅用加減實(shí)現(xiàn)的二分查找的算法是Mihai P?tra?cu 提出的?(我也不確定)筐眷。那有了二分法搜索為什么又提出斐波那契搜索呢,是否斐波那契搜索比二分法搜索习柠,相信很多做完此題的讀者都會(huì)有這個(gè)疑問(wèn)浊竟,這里我在Stack Overflow幫大家找到了相應(yīng)的問(wèn)答,供大家參考:

Is fibonacci search faster than binary search?

大概的意思就是津畸,斐波那契查找的時(shí)間復(fù)雜度還是O(log2n )振定,但是與折半查找相比,對(duì)磁盤的操作更省力肉拓,因此后频,斐波那契查找的運(yùn)行時(shí)間理論上比折半查找小。最后我們對(duì)斐波那契搜索做個(gè)更加詳細(xì)的說(shuō)明:

斐波那契搜索就是在二分查找的基礎(chǔ)上根據(jù)斐波那契數(shù)列進(jìn)行分割的暖途。在斐波那契數(shù)列找一個(gè)等于略大于查找表中元素個(gè)數(shù)的數(shù)F[n]卑惜,將原查找表擴(kuò)展為長(zhǎng)度為Fn,完成后進(jìn)行斐波那契分割驻售,即F[n]個(gè)元素分割為前半部分F[n-1]個(gè)元素露久,后半部分F[n-2]個(gè)元素,找出要查找的元素在那一部分并遞歸欺栗,直到找到毫痕。

答案

public class FibonacciSearch {

    private final int FI_SIZE = 20;

    public int fbSearch(int[] array, int target) {
        if (array == null || array.length == 0) {
            return -1;
        } else {
            int length = array.length;
            // 制造一個(gè)長(zhǎng)度為10的斐波數(shù)列
            int[] fb = makeFbArray(FI_SIZE);
            int k = 0;
            // 找出數(shù)組的長(zhǎng)度在斐波數(shù)列(減1)中的位置,將決定如何拆分
            while (length > fb[k] - 1) {
                k++;
            }
            // 構(gòu)造一個(gè)長(zhǎng)度為fb[k] - 1的新數(shù)列
            int[] temp = Arrays.copyOf(array, fb[k] - 1);
            for (int i = length; i < temp.length; i++) {
                if (i >= length) {
                    temp[i] = array[length - 1];
                }
            }
            int low = 0;
            int high = array.length - 1;
            while (low <= high) {
                int middle = low + fb[k - 1] - 1;
                if (temp[middle] > target) {
                    high = middle - 1;
                    k = k - 1;
                } else if (temp[middle] < target) {
                    low = middle + 1;
                    k = k - 2;
                } else {
                    if (middle <= high) {
                        // 若相等則說(shuō)明mid即為查找到的位置
                        return middle;
                    } else {
                        // middle的值已經(jīng)大于hight,進(jìn)入擴(kuò)展數(shù)組的填充部分,
                        //即最后一個(gè)數(shù)就是要查找的數(shù)迟几。
                        return high;
                    }
                }
            }
            return -1;
        }
    }


    public static int[] makeFbArray(int length) {
        int[] array = null;
        if (length > 2) {
            array = new int[length];
            array[0] = 1;
            array[1] = 1;
            for (int i = 2; i < length; i++) {
                array[i] = array[i - 1] + array[i - 2];
            }
        }
        return array;
    }
}

測(cè)試用例

public static void main(String[] args) {
    int[] array = {1, 5, 15, 22, 25, 31, 39, 42, 47, 49, 59, 68, 88, 88,
            88, 88, 88};
    FibonacciSearch search = new FibonacciSearch();
    System.out.println("result: " + search.fbSearch(array, 31));
}

代碼索引

FibonacciSearch.java

廣告

我的首款個(gè)人開(kāi)發(fā)的APP壁紙寶貝上線了消请,歡迎大家下載。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末类腮,一起剝皮案震驚了整個(gè)濱河市臊泰,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌蚜枢,老刑警劉巖缸逃,帶你破解...
    沈念sama閱讀 212,718評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異厂抽,居然都是意外死亡需频,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,683評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門修肠,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)贺辰,“玉大人,你說(shuō)我怎么就攤上這事∷腔” “怎么了莽鸭?”我有些...
    開(kāi)封第一講書(shū)人閱讀 158,207評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)吃靠。 經(jīng)常有香客問(wèn)我硫眨,道長(zhǎng),這世上最難降的妖魔是什么巢块? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,755評(píng)論 1 284
  • 正文 為了忘掉前任礁阁,我火速辦了婚禮,結(jié)果婚禮上族奢,老公的妹妹穿的比我還像新娘姥闭。我一直安慰自己,他們只是感情好越走,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,862評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布棚品。 她就那樣靜靜地躺著,像睡著了一般廊敌。 火紅的嫁衣襯著肌膚如雪铜跑。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 50,050評(píng)論 1 291
  • 那天骡澈,我揣著相機(jī)與錄音锅纺,去河邊找鬼。 笑死肋殴,一個(gè)胖子當(dāng)著我的面吹牛囤锉,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播疼电,決...
    沈念sama閱讀 39,136評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼嚼锄,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼减拭!你這毒婦竟也來(lái)了蔽豺?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,882評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤拧粪,失蹤者是張志新(化名)和其女友劉穎修陡,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體可霎,經(jīng)...
    沈念sama閱讀 44,330評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡魄鸦,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,651評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了癣朗。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片拾因。...
    茶點(diǎn)故事閱讀 38,789評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出绢记,到底是詐尸還是另有隱情扁达,我是刑警寧澤,帶...
    沈念sama閱讀 34,477評(píng)論 4 333
  • 正文 年R本政府宣布蠢熄,位于F島的核電站修档,受9級(jí)特大地震影響梯影,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,135評(píng)論 3 317
  • 文/蒙蒙 一发魄、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧纲刀,春花似錦雅潭、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,864評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至壁熄,卻和暖如春帚豪,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背草丧。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,099評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工狸臣, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人昌执。 一個(gè)月前我還...
    沈念sama閱讀 46,598評(píng)論 2 362
  • 正文 我出身青樓烛亦,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親懂拾。 傳聞我的和親對(duì)象是個(gè)殘疾皇子煤禽,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,697評(píng)論 2 351