日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

arry-718 Maximum Length of Repeated Subarray

發布時間:2023/12/10 编程问答 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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)

public int findLength(int[] A, int[] B) {int len1 = A.length;int len2 = B.length;int maxLen = 0;for(int i=0;i<len1;i++){int j = 0;while(j<len2){if(A[i] == B[j]){int count = 0;int idxA = i;int idxB = j;while(idxA<len1 && idxB <len2 && A[idxA++] == B[idxB++]) count++;maxLen = Math.max(maxLen,count);}j++;}}return maxLen;}

學習:動態規劃。上面分析是以數組的起點開始思考,動態規劃以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。

public int findLengthV2(int[] A, int[] B) {if (A == null || B == null)return 0;int m = A.length;int n = B.length;int[][] dp = new int[m][n];int maxLen = 0;for (int i = 0; i < m; i++) {for (int j = 0; j < n; j++) {if (j == 0 || i == 0) {dp[i][j] = (A[i] == B[j] ? 1 : 0);} else if (A[i] == B[j]) {dp[i][j] = 1 + dp[i - 1][j - 1];maxLen = Math.max(maxLen, dp[i][j]);}}}return maxLen;}

思考:讓我不能理解的地方是都是兩層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)為子數組終點考慮問題,竟然速度就快多了。這就是換個思路?再看看下面這段代碼。

public int findLength(int[] a, int[] b) {int m = a.length, n = b.length;if (m == 0 || n == 0) return 0;int[][] dp = new int[m + 1][n + 1];int max = 0;for (int i = m - 1; i >= 0; i--)for (int j = n - 1; j >= 0; j--)max = Math.max(max, dp[i][j] = a[i] == b[j] ? 1 + dp[i + 1][j + 1] : 0);return max; }

這個思路是以(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的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。