面試 6:拓展性更好的代碼,更容易拿到 Offer

 

今天給你們帶來的是 《劍指 Offer》習題:調整數組順序使奇數位於偶數前面,純 Java 實現但願你們多加思考。java

面試題:輸入一個整型數組,實現一個函數來調整該數組中的數字的順序,使得全部奇數位於數組的前半部分,全部偶數位於數組的後半部分,但願時間複雜度儘可能小。程序員

看到這道題,想必大多數人都是能一下就想到從頭至尾掃描一遍數組,而後遇到奇數就移動到最前面,遇到偶數就移動到最後面的思路,因而便有了下面的代碼。面試

注:《劍指 Offer》上面的 「遇到奇數移動到最前面,遇到偶數也移動到最後面」其實只須要作其中一種便可。算法

public class Test14 { private static int[] reOrderArray(int[] arr) { for (int i = 0; i < arr.length; i++) { // 遇到奇數就放到最前面 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] + " "); } } } 

上面的代碼當然能達到功能,但時間複雜度上徹底不能恭維。每找到一個奇數,咱們老是要去移動很多個位置的數。設計模式

等等。數組

咱們上面算法最大的問題在於移動,咱們可否不作這個移動呢?ide

固然是能夠的。題目要求全部奇數都應該在偶數前面,因此咱們應該只須要維護兩個下標值,讓一個下標值從前日後遍歷,另一個下標值從後往前遍歷,當發現第一個下標值對應到偶數,第二個下標值對應到奇數的時候,咱們就直接對調兩個值。直到第一個下標到了第二個下標的後面的時候退出循環。函數

咱們有了這樣的想法,能夠先拿一個例子在心中走一遍,若是沒有問題再寫代碼,這樣也可讓面試官知道,咱們並非那種上來就開始寫代碼不考慮全面的程序員。spa

  1. 假定輸入的數組是 {1,2,3,4,5};
  2. 設定 odd = 0,表明第一個下標;even = arr.length = 4;
  3. 從前日後移動第一個下標 odd,直到它等於偶數,即當 odd = 1 的時候,咱們中止移動;
  4. 再從後往前移動下標 even,直到它等於奇數,即當 even = 4 的時候,咱們中止移動;
  5. 知足 arr[odd] 爲偶數,arr[even] 爲奇數,咱們對調兩個值,獲得新數組 {1,5,3,4,2};
  6. 繼續循環,此時 odd = 3,even = 2,不知足 odd < even 的條件,退出循環,獲得的數組符合條件;

心中默走一遍沒問題後,開始手寫代碼:設計

public class Test14 { private static int[] reOrderArray(int[] arr) { int odd = 0, even = arr.length - 1; // 循環結束條件爲 odd >= even while (odd < even) { // 第一個下標爲偶數的時候中止 while (odd < even && Math.abs(arr[odd]) % 2 != 0) { odd++; } // 第二個下標爲奇數的時候中止 while (odd < even && Math.abs(arr[even]) % 2 == 0) { even--; } // 找到後對調兩個值 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

若是是面試應屆畢業生或者工做時間不長的程序員,面試官可能會滿意前面的代碼,但若是應聘者申請的是資深 的開發崗位,那面試官可能會接着問幾個問題。

  • 面試官:若是把題目改爲把數組中的數組按照大小分爲兩部分,全部的負數都在非負整數的前面,該怎麼作?
  • 應聘者:這很簡單,能夠從新定義一個函數,在新的函數裏,只要修改第二個和第三個 while 循環裏面的判斷條件就行了。
  • 面試官:若是再把題目改改,變成把數組中的數分爲兩部分,能被 3 整除的數都在不能被 3 整除的數的前面,怎麼辦?
  • 應聘者:咱們仍是能夠定義一個新的函數,在這個函數中......
  • 面試官:(打斷應聘者的話),難道就沒有更好的方法?

這個時候應聘者應該要反應過來,面試官期待咱們能提供的不只僅是解決一個問題的辦法,而是解決一系列同類型問題的通用方法。咱們在作解法的時候不能只想着解決當前的問題就好。在《大話設計模式》中,講解了一個很是有意思的事情就是大鳥讓小菜作商場促銷活動的時候,各類改變需求,把小菜繞的雲裏霧裏。

《大話設計模式》PDF 版本能夠在公衆號後臺回覆「大話設計模式」便可獲取。

是呀,哪有不變的需求,需求不變,咱們哪來那麼多活幹呀?不過要是,咱們事先就作了這樣的準備,省下來的時間那不是正好又能夠去玩一盤吃雞洛?

回到面試官新提出的兩個問題來,咱們其實新的函數都只須要更改第二個和第三個 while 循環裏面的判斷條件,而其它都是不須要動的。

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; // 循環結束條件爲 odd >= even while (odd < even) { // 第一個下標爲偶數的時候中止 while (odd < even && !iCheck.function(arr[odd])) { odd++; } // 第二個下標爲奇數的時候中止 while (odd < even && iCheck.function(arr[even])) { even--; } // 找到後對調兩個值 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(); } } 

寫這玩意兒的時候,我心裏是拒絕的,因爲 Java 沒有 Python 同樣方便的函數指針,我想了想只想到了用接口方式來處理。要是有其餘實現方式的但願你們能在評論區留言~

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

相關文章
相關標籤/搜索