Array 總結
source:: 代码随想录
#clippings
數組理論基礎
數組是非常基礎的數據結構,在面試中,考察數組的題目一般在思維上都不難,主要是考察對代碼的掌控能力
也就是說,想法很簡單,但實現起來 可能就不是那麼回事了。
首先要知道數組在內存中的存儲方式,這樣才能真正理解數組相關的面試題
**數組是存放在連續內存空間上的相同類型數據的集合。**數組可以方便的通過下標索引的方式獲取到下標下對應的數據。
舉一個字符數組的例子,如圖所示:
需要兩點注意的是
- 數組下標都是從0開始的。
- 數組內存空間的地址是連續的
正是因為數組的在內存空間的地址是連續的,所以我們在刪除或者增添元素的時候,就難免要移動其他元素的地址。
例如刪除下標為3的元素,需要對下標為3的元素後面的所有元素都要做移動操作,如圖所示:
而且大家如果使用C++的話,要注意vector 和array的區別,vector的底層實現是array,嚴格來講vector是容器,不是數組。
數組的元素是不能刪的,只能覆蓋。
那麼二維數組直接上圖,大家應該就知道怎麼回事了
那麼二維數組在內存的空間地址是連續的麼?
我們來舉一個Java的例子,例如: int[][] rating = new int[3][4];
, 這個二維數組在內存空間可不是一個 3*4
的連續地址空間
看了下圖,就應該明白了:
所以Java的二維數組在內存中不是 3*4
的連續地址空間,而是四條連續的地址空間組成!
在面試中,數組是必考的基礎數據結構。
其實數組的題目在思想上一般比較簡單的,但是如果想高效,並不容易。
我們之前一共講解了四道經典數組題目,每一道題目都代表一個類型,一種思想。
二分法
數組:每次遇到二分法,都是一看就會,一寫就廢 (opens new window)
這道題目呢,考察數組的基本操作,思路很簡單,但是通過率在簡單題裡並不高,不要輕敵。
可以使用暴力解法,通過這道題目,如果追求更優的算法,建議試一試用二分法,來解決這道題目
- 暴力解法時間複雜度:O(n)
- 二分法時間複雜度:O(logn)
在這道題目中我們講到了循環不變量原則,只有在循環中堅持對區間的定義,才能清楚的把握循環中的各種細節。
二分法是算法面試中的常考題,建議通過這道題目,鍛煉自己手撕二分的能力。
雙指針法
雙指針法(快慢指針法):通過一個快指針和慢指針在一個for循環下完成兩個for循環的工作。
- 暴力解法時間複雜度:O(n^2)
- 雙指針時間複雜度:O(n)
這道題目迷惑了不少同學,糾結於數組中的元素為什麼不能刪除,主要是因為以下兩點:
- 數組在內存中是連續的地址空間,不能釋放單一元素,如果要釋放,就是全釋放(程式運行結束,回收內存棧空間)。
- C++中vector和array的區別一定要弄清楚,vector的底層實現是array,封裝後使用更友好。
雙指針法(快慢指針法)在數組和鏈表的操作中是非常常見的,很多考察數組和鏈表操作的面試題,都使用雙指針法。
滑動窗口
本題介紹了數組操作中的另一個重要思想:滑動窗口。
- 暴力解法時間複雜度:O(n^2)
- 滑動窗口時間複雜度:O(n)
本題中,主要要理解滑動窗口如何移動 窗口起始位置,達到動態更新窗口大小的,從而得出長度最小的符合條件的長度。
滑動窗口的精妙之處在於根據當前子序列和大小的情況,不斷調節子序列的起始位置。從而將O(n^2)的暴力解法降為O(n)。
如果沒有接觸過這一類的方法,很難想到類似的解題思路,滑動窗口方法還是很巧妙的。
模擬行為
模擬類的題目在數組中很常見,不涉及到什麼算法,就是單純的模擬,十分考察大家對代碼的掌控能力。
在這道題目中,我們再一次介紹到了循環不變量原則,其實這也是寫程式中的重要原則。
相信大家有遇到過這種情況: 感覺題目的邊界調節超多,一波接著一波的判斷,找邊界,拆了東牆補西牆,好不容易運行通過了,代碼寫的十分宂餘,毫無章法,其實真正解決題目的代碼都是簡潔的,或者有原則性的,大家可以在這道題目中體會到這一點。
這個圖是 代碼隨想錄知識星球 (opens new window) 成員:海螺人 (opens new window),所畫,總結的非常好,分享給大家。
從二分法到雙指針,從滑動窗口到螺旋矩陣,相信如果大家真的認真做了「代碼隨想錄」每日推薦的題目,定會有所收獲。
推薦的題目即使大家之前做過了,再讀一遍文章,也會幫助你提煉出解題的精髓所在。