本篇文章是對leetcode array和Top Interview Questions標籤下32道array類型題目的總結
leetcode 283. Move Zeroes
此題屬於數組交換型,交換數組中元素的位置以滿足某種條件
解:交換數組位置,一般使用兩個指針的辦法,已到達O(1) space 的效果
並且此題有個特殊之處,題目中將數組中的元素分爲0項和非0項,也可分爲數組分類型,數組分類型的問題,假如有n個類,往往不必全部考慮這n個類,只要將n-1個類處理完,那最後一類自然被處理完。如本題中,只要處理了非0類,那麼0類的數自然排到了末尾。
leetcode 169. Majority Element
此題屬於數組計數問題,要找到數組中出現次數最多的那個數
解:
- 首先觀察本題,發現此題可以從大問題分解爲小問題,因此非常適合使用分治法
- 多數投票算法(Boyer-Moore Voting Algorithm)
論文翻譯:假設有一羣投票的人,每個人都會投票個某個候選人。爲了選擇最終贏的選取的候選人,可以採用這樣的選舉方式:每個投票人找到其他的投票人,並且這個投票人支持的候選不同於自己的支持的候選人,PK過後,這一對投票人同時出局。經過全部的PK之後,那麼還沒有出局的投票人支持的候選人,就有可能是最終的選舉勝利者(獲得半數以上的選票)。最後,選舉主席,需要檢查這位可能贏得選舉的候選人的票數,來確認他是否贏得了選舉。
https://www.cnblogs.com/javanerd/p/6262249.html
因此,數組計數問題可以考慮摩爾投票算法 - 數字數量上的問題,最後會反應到32位上的每一位,因此可以從位操作的角度出發
leetcode 268. Missing Number
此題的特點在於限制了數組中出現數的範圍,尋找缺失的那一個
解:
- 根據數組的和與每個數的關係,可以得到缺失數
- 數組位置i及其存儲的值nums[i] 之間的關係,因爲一個數異或它本身爲0,而數組位置0~n-1,數組存儲的值包含 0 ~ n,又因爲異或具有交換律,所以將數組位置 i 與nums[i]異或,最後的結果便是缺失的數
leetcode 1. Two Sum
尋找數組中是否有特定的數,可以通過hash來減少查找時間
解:
- 使用hash減少查找時間,因爲用hash可以達到O(1)的查找時間
leetcode 53. Maximum Subarray
尋找數組中的連續最大和子序列,屬於尋找數組區間(不像上一道題是尋找某個數)
解:
- 觀察本題,發現此題仍然可以從大問題分解爲小問題,因此使用分治法
- 動態規劃,區間的問題非常適合動態規劃。而且發現在數組中,i 位置的情況是和 i-1情況相關的,因此使用dp
- 貪心, 發現 i 位置只需要依賴 i-1 位置的情況(在 i-1 情況明確時), 可以將動態規劃簡化爲貪心
leetcode 26. Remove Duplicates from Sorted Array
此題特點:數組元素出現重複
解:
- 使用兩根指針,一根指非重複數字,一根指向重複數字,並通過while循環跳過重複數組
- 也可看做數組分類問題
Leectode 88. Merge Sorted Array
此題特點:合併問題
解:
- 使用兩根指針,合併時從後往前合併,這樣就不需要考慮從前往後排時,要將後面的數字統一往後移動一格的問題。正向遍歷困難時,通常可以考慮反向遍歷
Leetcode 189. Rotate Array
此題特點:數組反轉
解:
- 使用循環替代
- 先反轉整個數組,然後再翻轉前k個元素,再翻轉後n-k個元素
leetcode 238. Product of Array Except Self
此題特點:數組區間
解:
- 使用兩個動態數組。leftDp[i] 表示i左邊的數的乘積,rightDp[i] 表示i右邊的數的乘積,那麼res[i] = leftDp[i] * leftDp[i]
- 發現 i 只與 i-1/i+1有關,因此可以將動態數組簡化爲1個變量
leetcode 78. Subsets
得到數組中所有的子集,屬於排列組合型
解:
- 回溯法,find裏面的循環是尋找第n層遞歸的起點,依次從前往後添加元素,以避免重複,第n層遞歸時,添加長度爲n的子集。要注意,回溯爲了消除前一次的影響,在回溯完之後,要移除回溯前添加的數
leetcode 287. Find the Duplicate Number
此題特點:數組重複
解:
- 檢測重複問題,可以使用環檢測算法,兩根指針
https://blog.csdn.net/xyzxiaoxiong/article/details/78761940 - 二分查找
使用鴿籠原理,當數組內的數<= mid的個數多餘mid時,將search範圍放在mid~high,
當個數小於等於mid時,將search範圍放在low~mid,最後返回low/high(指的是索引)
巧妙的運用二分法
如n=10,mid=5,如果數組內小於等於5的個數多餘5個,那麼根據鴿籠原理,重複的數必在1~5內
leetcode 48. Rotate Image
特點:屬於數組交換問題,交換位置
解:
- 先根據斜對稱軸對摺,再根據中線y軸對摺
leetcode 62. Unique Paths
特點:沒有特點
解:
- 很明顯的動態規劃,數組 位置 i 上的情況依賴於附近位置的情況
Leetcode 289. Game of Life
特點: 根據某個規則,修個整個數組
解:
- 使用輔助數組,記錄修改之前的情況
- 不適用輔助數組,在原位置做標記,標記該位置做了修改或者需要修改,要注意做的標記不會影響到邏輯判斷
leetcode 11. Container With Most Water
特點:尋找符合要求的數組區間
解:
- 使用兩根指針,思考邏輯鏈:算面積->需要知道長寬-> 寬的話取決於兩邊短的一邊-> 兩邊-> 兩個指針法
每次移動短的那一段,因爲如果移動大的,那麼在另一端不變的情況下,水量可能會變小,首先寬變小一位,而高度始終是以小的算的。相對來說移動小的,在寬度變小的情況下,更容易獲得更大的面積
leetcode 75. Sort Colors
特點: 數組交換,數組分類問題
解:
- 將數組分爲三類0類、1類、2類,對0和1兩類進行交換,當交換完成時,2類也自動完成
需要在數組上交換而不引入額外空間-> 兩根指針
leetcode 105. Construct Binary Tree from Preorder and Inorder Traversal
特點:並無什麼特點
leetcode 79. Word Search
解:
- 回溯法,記錄訪問軌跡,注意在這個分支回溯完成後,需要把訪問數組中該位置置回原來的值
- 也可以不適用輔助數組記錄訪問,可以訪問時將本位置的數標記,置爲不會影響邏輯的其他數字,回溯完成時重新置回原來的數,這裏有一個問題,難道不記錄原來的數是什麼嗎?使用異或的性質,一個數異或本身爲0, 設原來的數爲A,回溯前A^256, 回溯後A ^ 256 就變回原來的A了
leetcode 73. Set Matrix Zeroes
特點:根據某項規則,修改整個數組
解:
- 使用輔助數組
- 進行標記,但要注意,這裏標記如果原位置標記的話,會對後面的判斷造成影響,所以對行首/列首進行標記。這樣只需要對行首/列首單獨處理即可
leetcode 162. Find Peak Element
尋找數組中是否有特定的數,使用二分查找
解:
- 線性掃描,遍歷每一個數,比較是否左邊的數要低一點,右邊的數要高一點。當然,如果發現右邊的數要低一點,就沒有必要再看右邊的數是否符合,直接看右邊的數的下一個數
- 這樣的題使用二分查找,一開始還是很驚奇的,因爲印象中都是對有序數組才使用二分法,但這是對二分法的誤解,要理解二分法的精髓在於在每一步都減少待搜索的區間
考慮本題,一個數mid根據和其右邊的數進行比較,可以得到該數是在下降的斜坡上還是在上升的斜坡,如果右邊的數更小,可以認爲是在下降的斜坡上,那麼峯值一定是在mid的左邊(包含其本身);如果右邊的數更大,可以認爲是在上升的斜坡上,那麼峯值一定是在mid的右邊,所以搜索範圍可以限制在mid及其右邊的子數組
當然,比如右邊的數比mid更大,是在上升的斜坡中,將捨棄mid左邊的子數組中也可能存在peak元素,但本題不是求最大的數,本題只要求找到一個peak即可,甚至邊界值(i=0,i=n-1)也算peak,所以纔可以這樣使用二分法
使用二分法減少搜索空間
leetcode 56. Merge Intervals
特點:數組區間問題,排序處理
解:將每個區間進行排序,按照start進行排序,start小的排在前面,遍歷排序後的intervals,如果第n個interval的end < 第n+1個的interval的start,那麼就將第n個interval當作一個新的interval加入結果中。如果第n個interval的end >= 第n+1個的interval的start,那麼就進行合併,end取兩個區間中最大那一個
leetcode 34. Find First and Last Position of Element in Sorted Array
特定: 尋找數組中特定的數,使用二分查找
解:
- 遍歷數組找到最大最小
- 使用二分查找,減小搜索空間。
按照正常binary search首先在mid處找到一個target,因爲數組已經排序好了,如果還有其他的target,那一定是在target的左邊還有右邊,如果有,那就分別以mid-1作爲最右邊界/mid+1作爲最左邊界繼續查找,得到position更小/更大的數
leetcode 33.Search in Rotated Sorted Array
特點:尋找數組中特定的數,使用二分查找
解:
- 觀察題目發現,因爲數組被旋轉了,所以可以確定,左邊被旋轉的那一部分的第一個數比右邊被旋轉的部分都大,右邊被旋轉的最後一個數也是比左邊被旋轉的所有數都小,所以每次二分查找時,判斷mid的左邊和右邊是否正常,比較target和nums[start]的大小關係,如果nums[start] 比 target大,說明target應該位於mid的右邊
leetcode 55. Jump Game
特點:
解:
- 自頂向下動態規劃,從method 1中我們可以看出,有些位置會重複遍歷,因此我們引入記憶化搜索,還會回溯,但每到一個位置i時,先查看該位置是否是能夠到達終點的位置(GOOD), 還是不能到達終點的位置(BAD),如果是不知道的位置(UNKNOWN),則遍歷這個位置
通過使用dp降低了複雜度,存儲了index i是否能到達終點的結果,當再經過這些index的時候不再需要計算! - 從method 3 中再次得到啓發,如果在位置i,且i~nums[i]+i這之中有一個GOOD INDEX,那麼代表位置i也是個GOOD INDEX
遍歷完如果lastPos = 0 則表示起點也是good Index,那麼從起點也可以跳到終點 - 當方法超時的時候)發現是不是有些步驟被重複計算,如果有重複計算,那麼就引入動態規劃
- 反向思考,問的是從起點到終點,如果能從終點到起點,結果也是等價的
leetcode 54. Spiral Matrix
特點:遍歷數組
解:
- method1 中 if和else過多過於繁雜,觀察題目我們可以發現,遍歷的方向是有順序的,永遠是往右,往下,往左,往上。因此,我們可以通過加法+求餘來得到下一個方向,因此,也能夠知道x,y該加還是該減,還是該不變
dr 表示row上的操作,dc 表示在column上的操作,當往左或往右時,行數不變,因此dr[0]/dr[2]都爲0
如果遍歷的方向是有規律的,是有循環的,那麼可以使用加法和求餘來控制方向!
leetcode 152. Maximum Product Subarray
特定:數組區間型
解:
- 單純用Maximum Sum Subarray的方法來做本道題是錯的,問題就在於dp[1]可能不僅和dp[i-1]有關,甚至和dp[i-2]有關,例如負,正,負的情況,在這樣的情況下,dp不僅需要記錄以i-1結尾的最大積,也需要記錄以i-1結尾的最小積,因爲如果異數相乘,就變成了一個負數
- 使用一個變量代替數組,當動態規劃數組中,dp[i]只與dp[i-1]相關,那麼這個時候可以用一個變量代替dp數組
- 動態規劃中弄清楚,當前位置的數究竟和附近哪幾個位置有關
leetcode 15. 3Sum
特點:尋找數組中特定的數
解:
- 3sum問題轉換爲2sum問題,然後再用2sum的辦法解決。這裏使用兩個指針的方
- 在使用兩根指針的時候,考慮一下是否需要排序,讓指針的移動更具有方向性
- 當處理去除重複性問題時,既可以使用set自動去重,也可以進行排序,當數重複的時候便跳過
leetcode 42. Trapping Rain Water
特定: 和leetcode 11一樣,着眼於每個位置i能夠積累多少水
解:
- 先找到數組中bar高度最高中最後一個的索引(因爲可能存在多個高度一樣的bar)
還是以每個位置i上能積累多少水量的思想計算,從左往右遍歷時,每次遍歷到位置i,只要在i+1~maxIndex這片區域中有連續的小於height[i]的bar(j),就證明這個bar可以積累水,並且積水量等於height[i]-height[j]
從右往左也是相同的
爲了避免重複計算,會跳過已經計算過水的索引
leetcode 128. Longest Consecutive Sequence
特點:尋找數組區間
解:
- 滑動窗口 利用set的特性,不斷地remove
使用一個set,對每一個數,檢查是否有它的前繼和後繼,如果有則推進,感覺相當於滑動窗口的變種,使用remove方法可以減少遍歷的數據量
leetcode 84. Largest Rectangle in Histogram
特點:數組區間問題
解:
- 分治法,RMQ思想,區間最值
http://dongxicheng.org/structure/lca-rmq/
https://blog.csdn.net/qq_41311604/article/details/79900893 - 等正式複習完補充
leetcode 41. First Missing Positive
leetcode 4. Median of Two Sorted Arrays
問題特點:
- 數組交換
283、48 - 數組分類
26、 - 數組計數
169、 - 限制數組中出現數的範圍
268、 - 數組區間
53、238、11、56、152、128、42、84 - 數組元素重複
26、287 - 合併問題
88、 - 排列組合
78、 - 根據某個規則,修改整個數組
289、73
啓示(array類型問題可以採用的方法):
- 兩根指針
主要是應對數組交換、分類等問題,將space cost限制在O(1)
如果是重複爲題,通過while循環跳過重複數組 - 如果觀察問題,發現問題可以分解爲小的問題,採用分治法
- 多數投票算法
- 使用位操作解決數字計數問題
- 尋找數組中是否有特定的數,可以通過hash來減少查找時間
- 如果數組位置i及其存儲的值nums[i] 有對應關係,可以考慮異或
- (數組區間)如果發現數組i位置的情況是和 依賴於附近位置情況,那麼可以使用動態規劃
- 如果動態規劃中, 發現 i 位置只需要依賴 i-1 位置的情況(在 i-1 情況明確時), 可以將動態規劃簡化爲貪心
- 數組反轉
(1)使用循環代替
(2)先反轉整個數組,然後再翻轉前k個元素,再翻轉後n-k個元素 - 排列組合型,使用回溯法,find裏面的循環是尋找第n層遞歸的起點,依次從前往後添加元素,以避免重複,第n層遞歸時,添加長度爲n的子集。要注意,回溯爲了消除前一次的影響,在回溯完之後,要移除回溯前添加的數
- 檢測重複問題,也可以使用兩根指針,使用環檢測算法
- 二分查找,查找數組中的某個數,可以使用二分查找減少數組的搜索空間,不一定要求數組是有序的,只要能夠按照二分查找的思想,每次捨棄一半的無用的查找空間
(1)leetcode 287
使用鴿籠原理,當數組內的數<= mid的個數多餘mid時,將search範圍放在mid~high,
當個數小於等於mid時,將search範圍放在low~mid,最後返回low/high(指的是索引)
巧妙的運用二分法
如n=10,mid=5,如果數組內小於等於5的個數多餘5個,那麼根據鴿籠原理,重複的數必在1~5內
(2)leetcode 162
這樣的題使用二分查找,一開始還是很驚奇的,因爲印象中都是對有序數組才使用二分法,但這是對二分法的誤解,要理解二分法的精髓在於在每一步都減少待搜索的區間
考慮本題,一個數mid根據和其右邊的數進行比較,可以得到該數是在下降的斜坡上還是在上升的斜坡,如果右邊的數更小,可以認爲是在下降的斜坡上,那麼峯值一定是在mid的左邊(包含其本身);如果右邊的數更大,可以認爲是在上升的斜坡上,那麼峯值一定是在mid的右邊,所以搜索範圍可以限制在mid及其右邊的子數組
(3)leetcode 34
按照正常binary search首先在mid處找到一個target,因爲數組已經排序好了,如果還有其他的target,那一定是在target的左邊還有右邊,如果有,那就分別以mid-1作爲最右邊界/mid+1作爲最左邊界繼續查找,得到position更小/更大的數
(4)leetcode 33
觀察題目發現,因爲數組被旋轉了,所以可以確定,左邊被旋轉的那一部分的第一個數比右邊被旋轉的部分都大,右邊被旋轉的最後一個數也是比左邊被旋轉的所有數都小,所以每次二分查找時,判斷mid的左邊和右邊是否正常,比較target和nums[start]的大小關係,如果nums[start] 比 target大,說明target應該位於mid的右邊 - 回溯,根據某個規則,修改整個數組
(1)可以使用輔助數組
(2)不使用輔助數組,在原位置上做標記,要注意做的標記不會影響到邏輯判斷
(3) 如果是在回溯中做標記,爲了不記憶原來的數,使用異或的性質,一個數異或本身爲0, 設原來的數爲A,回溯前A^256, 回溯後A ^ 256 就變回原來的A了
(4)進行標記時要注意 這裏標記如果原位置標記的話,會對後面的判斷造成影響,所以對行首/列首進行標記。這樣只需要對行首/列首單獨處理即可 - 先對數組排序再處理,往往能減少複雜度
- 當方法超時的時候)發現是不是有些步驟被重複計算,如果有重複計算,那麼就引入動態規劃
- 反向遍歷,反向思考,問的是從起點到終點,如果能從終點到起點,結果也是等價的。
- 使用數組來控制遍歷的方向
遍歷的方向是有順序的,永遠是往右,往下,往左,往上。因此,我們可以通過加法+求餘來得到下一個方向,因此,也能夠知道x,y該加還是該減,還是該不變
dr 表示row上的操作,dc 表示在column上的操作,當往左或往右時,行數不變,因此dr[0]/dr[2]都爲0
如果遍歷的方向是有規律的,是有循環的,那麼可以使用加法和求餘來控制方向! - 動態規劃中弄清楚,當前位置的數究竟和附近哪幾個位置有關
- 在使用兩根指針的時候,考慮一下是否需要排序,讓指針的移動更具有方向性
- 當處理去除重複性問題時,既可以使用set自動去重,也可以進行排序,當數重複的時候便跳過
- 對於數組區間問題,可以考慮使用滑動窗口問題,同時通過hash減少查找時間,將查找時間限制在O(1)
簡略版:
- 兩根指針
- 二分查找
- 分治法
- 回溯
- 動態規劃
- 貪心
- hash減少查找時間(set/map)
- 位操作 異或
- 多數投票算法
- 環檢測算法
- 環檢測算法
- 反向遍歷
- 排序
- 數組控制遍歷方向
- 滑動窗口