arry-718 Maximum Length of Repeated Subarray
題目:Input:
A: [1,2,3,2,1]
B: [3,2,1,4,7]
Output: 3
Explanation:
The repeated subarray with maximum length is [3, 2, 1].
思路:要找到兩個數組中重復數據最長的子數組的長度。暴力枚舉:每個A的下標i,分別與B的每個下標j作為起點,判斷最長的重復數組長度。就像是移動兩個指針。
例如i=0,j分別為0,1,2,3,4的時候,重復數組的長度分別為0,0,1,0,0。
當i=2,j=0的時候,重復數組的長度是3。接著還要計算i=2,j=1。如此一直計算到最后。這里的一個問題是當計算i=2,j=0找數組找到i=4,j=2結束之后,還有必要查找i=2,j=1位起始節點的子數組嗎?有必要,在連續重復的數組中。例如數組A=[X,X,0,0,0,1],數組B=[0,0,0,0,1],可以看到以i=2,j=0,為起點,重復數組長度為3,;以i=2,j=1位起點,重復數組長度為4。所以這個暴力枚舉沒有可以省略操作的地方。
時間復雜度:A中每個元素都要和B中每個元素比較一次,O(m*n)
學習:動態規劃。上面分析是以數組的起點開始思考,動態規劃以i,j作為子數組的終點元素,考慮從(0,0)到(i,j)中,重復數組的最長長度。
分析遞歸方程式。還以題目中的A、B數組為例。假設i=3,j=1,A[3]=B[1],那么dp[3][1] = dp[2][0]+1。假設i=3,j=4,A[3]≠B[4]A[3]≠B[4],那么dp[3][4]=dp[2][3]。得出dp[i][j] = dp[i-1][j-1]+1 如果A[i]=B[j]。這里之所以dp[i][j]與dp[i-1][j-1]有關系,而不是跟dp[i][j-1]或者dp[i-1][j]有關系,是因為這是求重復數組的長度。而求重復數組肯定是兩個數組的下標同時移動。
分析初始化條件。如果i=0,如果A[i]=B[j]則dp[0][j]=1否則為0。如果j=0,如果A[i]=B[j]則dp[i][0]=1否則為0。
思考:讓我不能理解的地方是都是兩層for循環,時間復雜度都是O(m*n)。方法二就比方法一快。相比較之下方式一多出了
while(idxA<len1 && idxB <len2 && A[idxA++] == B[idxB++]) count++;這個步驟。方法二中只是簡單的加法操作,當然更快。這樣說來,方法一的時間復雜度就不是O(m*n)。當數組中重復元素多的情況下,兩者速度相差就更大了。例如以下數組:
[59,59,59,93,59,59,59,59,59,59,59,59,59,59,59,59…]
[59,59,59,91,59,59,59,59,59,59,59,59,59,59,59,59..]
還有讓我感覺神奇的地方是如果以(i,j)為子數組起點考慮問題,解決方法時間長;而以(i,j)為子數組終點考慮問題,竟然速度就快多了。這就是換個思路?再看看下面這段代碼。
這個思路是以(i,j)作為子數組的開始節點,dp[i][j]存儲以(i,j)為子數組起始節點的重復數組最長長度。這時候從最大的下標開始考慮。為什么從最大下標開始考慮,看下面的分析。
數組:A: [1,2,3,2,1] B: [3,2,1,4,7]
例如i=4,j=4,因為A[4]不等于B[4],所以dp[4][4]=0。
例如i=3,j=1,則dp[3][1]=dp[4][2]+1,應該是在以j=4,j=2這個數組重復數組最長長度+1,因為A[3]=B[1]。dp[3][1] 與dp[2][0]的關系就不是很確定。我可能因為向后移動了位置,重復數組變長,也可能變短。
開辟空間dp[m+1][n+1] ,而不是dp[m][n]是為了編碼方便。
所以:暴力枚舉與動態規劃是兩種思考問題的方式。動態規劃在找遞推關系的時候不是一定要有dp[i][j]與dp[i-1][j-1],也可能是dp[i+1][j+1]。根據題目的確定性關系確定遞推式。
參考資料:
網頁1
網頁2
總結
以上是生活随笔為你收集整理的arry-718 Maximum Length of Repeated Subarray的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Spring学习11-Spring管理各
- 下一篇: 最全的ASCII码对照表