如何進(jìn)入Google,面試算法之道:在雙升序二維數(shù)組中的快速查找

給定一個(gè)二維數(shù)組找颓,它的行和列都是已經(jīng)按升序排列粒竖,請?jiān)O(shè)計(jì)一個(gè)算法氧骤,對于給定某個(gè)值x呻疹,判斷該值是否包含在數(shù)組中。例如給定一個(gè)二維數(shù)組如下:
A = {
{2, 4, 6, 8 , 10},
{12, 14, 16, 18, 20},
{22, 24, 26, 28, 30},
{32, 34, 36, 38, 40},
{42, 44, 46, 48, 50},
}

如果給定的x值是34筹陵,那么算法返回該值所在的行和列刽锤,也就是3和2,如果x的值是35朦佩,那么算法返回該值不存在并思。

在我們以前的算法討論中曾經(jīng)提到過一個(gè)法則,當(dāng)看到有數(shù)組時(shí)语稠,首先想到的就是排序宋彼。如果看到排序弄砍,首先想到的是二分查找,對于給定數(shù)組输涕,它已經(jīng)排好序了音婶,那么我們可以考慮用二分查找來判斷給定元素是否在數(shù)組中。

我們先看最簡單的做法莱坎,最簡單的莫過于一個(gè)個(gè)查看衣式,也就是算法遍歷每一個(gè)元素,看看是否與給定數(shù)值相等檐什。這種做法算法復(fù)雜度是O(n*n)碴卧。

第二種做法就是使用二分查找,由于每一行都是升序排列的厢汹,那么我們可以對應(yīng)于一行螟深,先用二分查找法,探尋給定元素是否在某一行烫葬,如果不再這行界弧,那么我們選擇新一行,再次使用二分查找去檢測給定元素是否存在給定行搭综。第二種做法效率比第一種要高垢箕,因?yàn)槎植檎业膹?fù)雜度是lg(n),因此算法的復(fù)雜度是O(n*lg(n))兑巾。

我們能否更進(jìn)一步条获,找到更好的算法呢?題目給定的特征是蒋歌,數(shù)組的行和列都是升序排序的帅掘,第二種做法只利用了行是升序排列這一性質(zhì),對于列的升序排列并未利用到堂油,如果能夠利用到這一特性的話修档,那么我們就可以設(shè)計(jì)出更高效的算法,由此我們得到第三種算法如下,假設(shè)數(shù)組的長度為n:

1, 用x與A[0][n-1]比較府框,如果 x < A[0][n-1], 那根據(jù)數(shù)組每一列都是升序排序的特性吱窝,我們可以排除掉數(shù)組的最后一列。

2, 如果x > A[0][n-1], 那么根據(jù)數(shù)組每一行按照升序排列的特性迫靖,我們就可以排除掉數(shù)組的第0行院峡。

3, 如果x == A[0][n-1], 算法直接返回。

4, 如果算法查詢的行數(shù)超過n,或者列數(shù)小于0系宜,那表明數(shù)組不包含給定元素照激。

根據(jù)上述算法描述,我們給出算法的代碼實(shí)現(xiàn)如下:


public class TwoDArraySearch {
    private int[][] searchArray;
    private int seachValue;
    
    private int row = 0;
    private int col = 0;
    
    public int getRow () {
        return this.row;
    }
    
    public int getCol () {
        return this.col;
    }
    
    public TwoDArraySearch(int[][] array, int val) {
        this.searchArray = array;
        this.seachValue = val;
        this.col = array[0].length - 1;
    }
    
    boolean search() {
        while (this.row < this.searchArray[0].length && this.col >= 0) {
            if (this.searchArray[this.row][this.col] == this.seachValue) {
                return true;
            }
            
            if (this.seachValue > this.searchArray[this.row][this.col]) {
                this.row++;
            }else if (this.seachValue < this.searchArray[this.row][this.col]) {
                this.col--;
            }
        }
        
        return false;
    }
   
}

在程序的主入口中盹牧,我們設(shè)計(jì)數(shù)據(jù)如下:

import java.util.AbstractMap;
import java.util.AbstractMap.SimpleEntry;
import java.util.Arrays;
import java.util.Map.Entry;
import java.util.Random;

public class Search {
    
    public static void main(String[] args) {
       int[][] array = {
               {2, 4, 6, 8 , 10},
               {12, 14, 16, 18, 20},
               {22, 24, 26, 28, 30},
               {32, 34, 36, 38, 40},
               {42, 44, 46, 48, 50},
       };
       
       TwoDArraySearch s = new TwoDArraySearch(array, 34);
       if (s.search() == true) {
           System.out.println("Array contains element which is in row " + s.getRow() + " and in col " + s.getCol());
       } else {
           System.out.println("Array does not contain the given element");
       }
    }
}

代碼先構(gòu)造了一個(gè)行和列都按照升序排列的數(shù)組实抡,并設(shè)置要查詢的數(shù)值為34欠母,顯然該值包含在數(shù)組中,然后調(diào)用TwoDArraySearch 的search()函數(shù)吆寨,上面代碼運(yùn)行后結(jié)果如下:

這里寫圖片描述

根據(jù)輸出結(jié)果赏淌,我們可以判斷,算法的實(shí)現(xiàn)是正確的啄清。

我們再看看算法的復(fù)雜度六水,根據(jù)算法步驟描述,每當(dāng)執(zhí)行步驟1或2時(shí)辣卒,算法都會排除掉一行或者一列的元素掷贾,這意味著,算法要檢測的元素?cái)?shù)量減少了n個(gè)荣茫,一個(gè)n*n的數(shù)組想帅,它只有n行和n列,也就是說啡莉,步驟1和2最多只能執(zhí)行n次港准,因此第三種算法的復(fù)雜度是O(n)。

更詳細(xì)的講解和代碼調(diào)試演示過程咧欣,請點(diǎn)擊鏈接

更多技術(shù)信息浅缸,包括操作系統(tǒng),編譯器魄咕,面試算法衩椒,機(jī)器學(xué)習(xí),人工智能哮兰,請關(guān)照我的公眾號:


這里寫圖片描述
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末毛萌,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子喝滞,更是在濱河造成了極大的恐慌朝聋,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,122評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件囤躁,死亡現(xiàn)場離奇詭異,居然都是意外死亡荔睹,警方通過查閱死者的電腦和手機(jī)狸演,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來僻他,“玉大人宵距,你說我怎么就攤上這事《洲郑” “怎么了满哪?”我有些...
    開封第一講書人閱讀 164,491評論 0 354
  • 文/不壞的土叔 我叫張陵婿斥,是天一觀的道長。 經(jīng)常有香客問我哨鸭,道長民宿,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,636評論 1 293
  • 正文 為了忘掉前任像鸡,我火速辦了婚禮活鹰,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘只估。我一直安慰自己志群,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,676評論 6 392
  • 文/花漫 我一把揭開白布蛔钙。 她就那樣靜靜地躺著锌云,像睡著了一般。 火紅的嫁衣襯著肌膚如雪吁脱。 梳的紋絲不亂的頭發(fā)上桑涎,一...
    開封第一講書人閱讀 51,541評論 1 305
  • 那天,我揣著相機(jī)與錄音豫喧,去河邊找鬼石洗。 笑死,一個(gè)胖子當(dāng)著我的面吹牛紧显,可吹牛的內(nèi)容都是我干的讲衫。 我是一名探鬼主播,決...
    沈念sama閱讀 40,292評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼孵班,長吁一口氣:“原來是場噩夢啊……” “哼涉兽!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起篙程,我...
    開封第一講書人閱讀 39,211評論 0 276
  • 序言:老撾萬榮一對情侶失蹤枷畏,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后虱饿,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體拥诡,經(jīng)...
    沈念sama閱讀 45,655評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,846評論 3 336
  • 正文 我和宋清朗相戀三年氮发,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了渴肉。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,965評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡爽冕,死狀恐怖仇祭,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情颈畸,我是刑警寧澤乌奇,帶...
    沈念sama閱讀 35,684評論 5 347
  • 正文 年R本政府宣布没讲,位于F島的核電站,受9級特大地震影響礁苗,放射性物質(zhì)發(fā)生泄漏爬凑。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,295評論 3 329
  • 文/蒙蒙 一寂屏、第九天 我趴在偏房一處隱蔽的房頂上張望贰谣。 院中可真熱鬧,春花似錦迁霎、人聲如沸吱抚。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽秘豹。三九已至,卻和暖如春昌粤,著一層夾襖步出監(jiān)牢的瞬間既绕,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評論 1 269
  • 我被黑心中介騙來泰國打工涮坐, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留凄贩,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,126評論 3 370
  • 正文 我出身青樓袱讹,卻偏偏與公主長得像疲扎,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子捷雕,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,914評論 2 355