1. 程式人生 > 實用技巧 >ARTS習慣(3)

ARTS習慣(3)

目錄

米羅說

  • 做難事必有所得

Algorithm

每週至少做一個Leetcode演算法題

【題目來源】

左程雲《程式設計師程式碼面試指南:IT名企演算法與資料結構題目最優解(第2版)》單調棧結構

【題目】

給定一個不含有重複值的陣列arr,找到每一個i位置左邊和右邊離i位置最近且值比arr[i]小的位置。返回所有位置相應的資訊。

【舉例】

輸入:{3,4,1,5,6,2,7}

返回:{

{-1,2}
{0,2}
{-1,-1}
{2,5}
{3,5}
{2,-1}
{5,-1}

}

注:-1表示不存在。

【要求】

如果arr的長度為N,解法的時間複雜度為O(N)

【解答】

單調棧是面試中常問的一種資料結構,讀者需要多做練習掌握這個題型。

我們先建立1個Stack<Integer>用來存放陣列的下標,開始時Stack為空。如果找到i位置左邊或者右邊離i最近且值小於arr[i]的元素,那麼棧從棧頂到棧底元素在陣列中的值必須嚴格遞減

遍歷arr,將下標放入Stack棧,檢查是否滿足嚴格遞減原則,假設遍歷到x下標時破壞了嚴格遞減原則,那麼x下面就是x左邊最近的小於arr[x]的值a,當前值就是x右邊最近的小於arr[x]的值b。下面證明上述的推理的正確性。

i位置(1)---------x位置(5)---------j位置(4)

假設x位置是被彈出的元素,j位置為當前值,i位置為x位置下面的元素。用假設法來證明:

1)假設(x,j)之間存在值小於5的數,那麼輪不到j將x彈出棧,存在的這個數就將x彈出棧了,所以(x,j)之間要麼沒有數,要麼值比5大,所以j位置是x右側距離x最近,且值小於5的位置

2)假設(i,x)之間存在值小於1的數,那麼該數會把i位置彈出,與題目假設矛盾;假設存在大於1且小於5的位置,那麼二者不會相鄰,與題目假設矛盾;假設存在大於5的位置,那麼5的出現將會把該位置彈出,從而i和x位置相鄰,中間沒有其他數。所以說,i=x-1位置是x位置左邊距離x最近的且值小於5的位置。

綜上證畢。

【參考程式碼】

 public static int[][] getNearAndLessNoRepeat(int[] arr){
        Stack<Integer> stack = new Stack<Integer>();
        int[][] res = new int[arr.length][2];
        int index = 0;
        for (int i = 0; i < arr.length; i++) {
            while (!stack.isEmpty() && arr[stack.peek()] > arr[i]) {
                index = stack.pop();
                int leftLessIndex = stack.isEmpty() ? -1 : stack.peek();
                res[index][0] = leftLessIndex;
                res[index][1] = i;
            }
            stack.push(i);
        }
        // 彈出剩餘的棧元素,這些元素沒有右邊最近小於位置
        while (!stack.isEmpty()) {
            index = stack.pop();
            int leftLessIndex = stack.isEmpty() ? -1 : stack.peek();
            res[index][0] = leftLessIndex;
            res[index][1] = -1;
        }
        return res;
    }

【思考討論】

  • 若陣列arr中含有重複值的元素,演算法該怎麼寫
  • 用單調棧結構實現:返回i位置左右最近大於arr[i]的集合

Review

閱讀並點評至少1篇英文技術文章

【原文】:Head First Java(2nd Editon)CH9 Life and Death of an Object

【譯文】:英文版原汁原味,語義準確,本書的寫作風格幽默,容易理解。讀者應重點關注作者是如何一步一步帶你帶你分析問題的,不必糾結細枝末節的東西。讀者也可移步Head First Java(第二版·中文版)

【點評】:

  • 位置

    • 棧:方法呼叫和區域性變數存放的地方

    • 堆:所有的物件呆的地方,例項變數待在物件裡

    • Methods are stacked:呼叫的method1方法被壓入棧,method1方法中呼叫method2方法,繼續將method2壓入棧。棧頂的方法總是當前執行的方法,method2方法執行完後,彈出,繼續執行method1方法。

    • 非基本型別變數持有物件的引用,待在棧,真正的物件待在堆

  • 建立物件

    • 通過new ClassName呼叫構造器來實現,構造器內部初始化重要的狀態,構造器可以overloaded(過載),構造器和方法有兩點區別:1)構造器沒有返回值;2)構造器的名字必須和類名一樣
    • super()只能用在構造器裡,並且只能是構造器的第一行程式碼。this()和super()一樣,因此二者不能共存,因為他們必須都要是構造器的第一行程式碼。
    • Constructor Chaining:subclass extends superclass ,那麼建立子類物件的同時,根據構造器的連鎖效應,父類的構造器也會自動呼叫,執行過程滿足棧的規律,父類構造器先完成,子類構造器後完成。
  • 回收物件

    • 物件的回收取決於它的引用變數,當引用變數失效時,物件就沒有可以被回收了。

    • 下面3中情形,物件滿足被GC的條件

      • 引用永久的離開作用域了

        // 方法結束時,d失效,Life物件失去了引用,
        void go() {
            Life d = new Life();
        }
        
      • 引用指向了一個新的物件

        Life d = new Life();
        d = new Life();	// d指向了新的物件,原來的物件失去了指向,不可達
        
      • 引用被賦值為null

        Life d = new Life();
        d = null; //顯示的賦值為null,原來的物件失去了指向,不可達
        

Tip

學習至少一個技術技巧

SpringBoot的自動裝配原理:從以下2個角度來認識自動裝配

  • 載入AutoConfiguration類

    Spring啟動依靠main方法啟動的,會呼叫SpringApplication.run()方法,執行run()方法時會有個重新整理容器的過程,通過解析註解和解析屬性配置檔案(application.yml)的方式,來把bean注入到容器裡邊。解析@SpringBootApplication註解的時候,@SpringBootApplication = @SpringBootConfiguration +@ComponentScan+@EnableAutoConfiguration,分別起到配置、元件掃描、開啟自動配置的作用,@EnableAutoConfiguration註解是核心註解,會開啟自動裝配,這個註解會@Import()進來一個AutoConfigurationSelector核心的類,這個selector類裡有個selectImports()方法通過SpringFactoriesLoader.loadFactoryNames()掃描的META-INF/spring.factories檔案,載入key為EnableAutoConfiguration的好多的AutoConfiguration的類,這些自動配置類裡有條件註解,他會根據我們引入的jar包和容器中的bean自動的把bean注入到容器裡邊,於是實現了自動裝配。

  • 引數繫結

    AutoConfiguration類通過Properties結尾的類來從屬性配置檔案(application.yml)中獲取類似於server.port的資訊,是通過@ConfigurationProperties註解來實現屬性繫結的

Share

分享一篇有觀點和思考的技術文章

推薦《修改程式碼的藝術》(美)Michael C. Feathers,一部小塊頭的著作,需要好好啃才能體會到作者的超強洞察力和功夫。

這裡放上電子版,試看之後覺得對你幫助很大,還是支援版權,買上一本書吧!

連結:https://pan.baidu.com/s/1piclbVvEu9kGRQK8KQ-JIQ
提取碼:nzdw