面試 6:調(diào)整數(shù)組順序使奇數(shù)位于偶數(shù)前面

今天給大家?guī)淼氖?《劍指 Offer》習(xí)題:調(diào)整數(shù)組順序使奇數(shù)位于偶數(shù)前面存哲,純 Java 實現(xiàn)希望大家多加思考斟叼。

面試題:輸入一個整型數(shù)組,實現(xiàn)一個函數(shù)來調(diào)整該數(shù)組中的數(shù)字的順序铣猩,使得所有奇數(shù)位于數(shù)組的前半部分股毫,所有偶數(shù)位于數(shù)組的后半部分,希望時間復(fù)雜度盡量小困介。

看到這道題大审,想必大多數(shù)人都是能一下就想到從頭到尾掃描一遍數(shù)組,然后遇到奇數(shù)就移動到最前面座哩,遇到偶數(shù)就移動到最后面的思路徒扶,于是便有了下面的代碼。

注:《劍指 Offer》上面的 「遇到奇數(shù)移動到最前面根穷,遇到偶數(shù)也移動到最后面」其實只需要做其中一種即可姜骡。

public class Test14 {

    private static int[] reOrderArray(int[] arr) {
        for (int i = 0; i < arr.length; i++) {
            // 遇到奇數(shù)就放到最前面
            if (Math.abs(arr[i]) % 2 == 1) {
                int temp = arr[i];
                // 先把 i 前面的都向后移動一個位置
                for (int j = i; j > 0; j--) {
                    arr[j] = arr[j - 1];
                }
                arr[0] = temp;
            }
        }
        return arr;
    }

    public static void main(String[] args) {
        int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9};
        arr = reOrderArray(arr);
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i] + " ");
        }
        System.out.println();

        int[] arr1 = {2, 4, 6, 8, 1, 3, 5, 7, 9};
        arr1 = reOrderArray(arr1);
        for (int i = 0; i < arr1.length; i++) {
            System.out.print(arr1[i] + " ");
        }
        System.out.println();

        int[] arr2 = {2, 4, 6, 8, 10};
        arr2 = reOrderArray(arr2);
        for (int i = 0; i < arr2.length; i++) {
            System.out.print(arr2[i] + " ");
        }
    }
}

上面的代碼固然能達(dá)到功能,但時間復(fù)雜度上完全不能恭維屿良。每找到一個奇數(shù)圈澈,我們總是要去移動不少個位置的數(shù)。

等等尘惧。

我們上面算法最大的問題在于移動康栈,我們能否不做這個移動呢?

當(dāng)然是可以的喷橙。題目要求所有奇數(shù)都應(yīng)該在偶數(shù)前面啥么,所以我們應(yīng)該只需要維護兩個下標(biāo)值,讓一個下標(biāo)值從前往后遍歷重慢,另外一個下標(biāo)值從后往前遍歷饥臂,當(dāng)發(fā)現(xiàn)第一個下標(biāo)值對應(yīng)到偶數(shù)逊躁,第二個下標(biāo)值對應(yīng)到奇數(shù)的時候似踱,我們就直接對調(diào)兩個值。直到第一個下標(biāo)到了第二個下標(biāo)的后面的時候退出循環(huán)稽煤。

我們有了這樣的想法核芽,可以先拿一個例子在心中走一遍,如果沒有問題再寫代碼酵熙,這樣也可以讓面試官知道轧简,我們并不是那種上來就開始寫代碼不考慮全面的程序員。

  1. 假定輸入的數(shù)組是 {1匾二,2哮独,3拳芙,4,5}皮璧;
  2. 設(shè)定 odd = 0舟扎,代表第一個下標(biāo);even = arr.length = 4悴务;
  3. 從前往后移動第一個下標(biāo) odd睹限,直到它等于偶數(shù),即當(dāng) odd = 1 的時候讯檐,我們停止移動羡疗;
  4. 再從后往前移動下標(biāo) even,直到它等于奇數(shù)别洪,即當(dāng) even = 4 的時候叨恨,我們停止移動;
  5. 滿足 arr[odd] 為偶數(shù)挖垛,arr[even] 為奇數(shù)特碳,我們對調(diào)兩個值,得到新數(shù)組 {1晕换,5午乓,3,4闸准,2}益愈;
  6. 繼續(xù)循環(huán),此時 odd = 3,even = 2夷家,不滿足 odd < even 的條件蒸其,退出循環(huán),得到的數(shù)組符合條件库快;

心中默走一遍沒問題后摸袁,開始手寫代碼:

public class Test14 {

    private static int[] reOrderArray(int[] arr) {
        int odd = 0, even = arr.length - 1;
        // 循環(huán)結(jié)束條件為 odd >= even
        while (odd < even) {
            // 第一個下標(biāo)為偶數(shù)的時候停止
            while (odd < even && Math.abs(arr[odd]) % 2 != 0) {
                odd++;
            }
            // 第二個下標(biāo)為奇數(shù)的時候停止
            while (odd < even && Math.abs(arr[even]) % 2 == 0) {
                even--;
            }

            // 找到后對調(diào)兩個值
            int temp = arr[odd];
            arr[odd] = arr[even];
            arr[even] = temp;

        }
        return arr;
    }

    public static void main(String[] args) {
        int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9};
        arr = reOrderArray(arr);
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i] + " ");
        }
        System.out.println();

        int[] arr1 = {2, 4, 6, 8, 1, 3, 5, 7, 9};
        arr1 = reOrderArray(arr1);
        for (int i = 0; i < arr1.length; i++) {
            System.out.print(arr1[i] + " ");
        }
        System.out.println();

        int[] arr2 = {2, 4, 6, 8, 10};
        arr2 = reOrderArray(arr2);
        for (int i = 0; i < arr2.length; i++) {
            System.out.print(arr2[i] + " ");
        }
        System.out.println();
    }
}

擴展性更好的代碼,能秒殺 Offer

如果是面試應(yīng)屆畢業(yè)生或者工作時間不長的程序員义屏,面試官可能會滿意前面的代碼靠汁,但如果應(yīng)聘者申請的是資深 的開發(fā)崗位,那面試官可能會接著問幾個問題闽铐。

  • 面試官:如果把題目改成把數(shù)組中的數(shù)組按照大小分為兩部分蝶怔,所有的負(fù)數(shù)都在非負(fù)整數(shù)的前面,該怎么做兄墅?
  • 應(yīng)聘者:這很簡單踢星,可以重新定義一個函數(shù),在新的函數(shù)里隙咸,只要修改第二個和第三個 while 循環(huán)里面的判斷條件就好了沐悦。
  • 面試官:如果再把題目改改成洗,變成把數(shù)組中的數(shù)分為兩部分,能被 3 整除的數(shù)都在不能被 3 整除的數(shù)的前面藏否,怎么辦泌枪?
  • 應(yīng)聘者:我們還是可以定義一個新的函數(shù),在這個函數(shù)中......
  • 面試官:(打斷應(yīng)聘者的話)秕岛,難道就沒有更好的方法碌燕?

這個時候應(yīng)聘者應(yīng)該要反應(yīng)過來,面試官期待我們能提供的不僅僅是解決一個問題的辦法继薛,而是解決一系列同類型問題的通用方法修壕。我們在做解法的時候不能只想著解決當(dāng)前的問題就好。在《大話設(shè)計模式》中遏考,講解了一個非常有意思的事情就是大鳥讓小菜做商場促銷活動的時候慈鸠,各種改變需求,把小菜繞的云里霧里灌具。

《大話設(shè)計模式》PDF 版本可以在公眾號后臺回復(fù)「大話設(shè)計模式」即可獲取青团。

是呀,哪有不變的需求咖楣,需求不變督笆,我們哪來那么多活干呀?不過要是诱贿,我們事先就做了這樣的準(zhǔn)備娃肿,省下來的時間那不是正好又可以去玩一盤吃雞洛?

回到面試官新提出的兩個問題來珠十,我們其實新的函數(shù)都只需要更改第二個和第三個 while 循環(huán)里面的判斷條件料扰,而其它都是不需要動的。

public class Test14 {

    interface ICheck {
        boolean function(int n);
    }

    public static class OrderEven implements ICheck {
        @Override
        public boolean function(int n) {
            return n % 2 == 0;
        }
    }

    private static int[] reOrderArray(int[] arr, ICheck iCheck) {
        int odd = 0, even = arr.length - 1;
        // 循環(huán)結(jié)束條件為 odd >= even
        while (odd < even) {
            // 第一個下標(biāo)為偶數(shù)的時候停止
            while (odd < even && !iCheck.function(arr[odd])) {
                odd++;
            }
            // 第二個下標(biāo)為奇數(shù)的時候停止
            while (odd < even && iCheck.function(arr[even])) {
                even--;
            }

            // 找到后對調(diào)兩個值
            int temp = arr[odd];
            arr[odd] = arr[even];
            arr[even] = temp;

        }
        return arr;
    }

    public static void main(String[] args) {
        OrderEven even = new OrderEven();
        int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9};
        arr = reOrderArray(arr,even);
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i] + " ");
        }
        System.out.println();

        int[] arr1 = {2, 4, 6, 8, 1, 3, 5, 7, 9};
        arr1 = reOrderArray(arr1,even);
        for (int i = 0; i < arr1.length; i++) {
            System.out.print(arr1[i] + " ");
        }
        System.out.println();

        int[] arr2 = {2, 4, 6, 8, 10};
        arr2 = reOrderArray(arr2,even);
        for (int i = 0; i < arr2.length; i++) {
            System.out.print(arr2[i] + " ");
        }
        System.out.println();

    }
}

寫這玩意兒的時候焙蹭,我內(nèi)心是拒絕的晒杈,由于 Java 沒有 Python 一樣方便的函數(shù)指針,我想了想只想到了用接口方式來處理孔厉。要是有其他實現(xiàn)方式的希望大家能在評論區(qū)留言~

好了拯钻,今天的面試講解,就先到這兒吧烟馅。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末说庭,一起剝皮案震驚了整個濱河市然磷,隨后出現(xiàn)的幾起案子郑趁,更是在濱河造成了極大的恐慌,老刑警劉巖姿搜,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件寡润,死亡現(xiàn)場離奇詭異捆憎,居然都是意外死亡,警方通過查閱死者的電腦和手機梭纹,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進店門躲惰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人变抽,你說我怎么就攤上這事础拨。” “怎么了绍载?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵诡宗,是天一觀的道長。 經(jīng)常有香客問我击儡,道長塔沃,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任阳谍,我火速辦了婚禮蛀柴,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘矫夯。我一直安慰自己鸽疾,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布训貌。 她就那樣靜靜地躺著肮韧,像睡著了一般。 火紅的嫁衣襯著肌膚如雪旺订。 梳的紋絲不亂的頭發(fā)上弄企,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天,我揣著相機與錄音区拳,去河邊找鬼拘领。 笑死,一個胖子當(dāng)著我的面吹牛樱调,可吹牛的內(nèi)容都是我干的约素。 我是一名探鬼主播,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼笆凌,長吁一口氣:“原來是場噩夢啊……” “哼圣猎!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起乞而,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤送悔,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體欠啤,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡荚藻,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了洁段。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片应狱。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖祠丝,靈堂內(nèi)的尸體忽然破棺而出疾呻,到底是詐尸還是另有隱情,我是刑警寧澤写半,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布罐韩,位于F島的核電站,受9級特大地震影響污朽,放射性物質(zhì)發(fā)生泄漏散吵。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一蟆肆、第九天 我趴在偏房一處隱蔽的房頂上張望矾睦。 院中可真熱鬧,春花似錦炎功、人聲如沸枚冗。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽赁温。三九已至,卻和暖如春淤齐,著一層夾襖步出監(jiān)牢的瞬間股囊,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工更啄, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留稚疹,地道東北人。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓祭务,卻偏偏與公主長得像内狗,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子义锥,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,916評論 2 344

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