未排序陣列中累加和為給定值的最長子陣列
題目
給定一個無序陣列arr,其中元素可正,可負,可0,給定一個整數k。
求arr所有的子陣列中累加和為k的最長子陣列長度。
分析
為了解答題目,引入一個概念,
s(i)代表子陣列arr[0..i]所有元素的累加和。那麼子陣列arr[j-1, i](0<=j<=i<arr.length)的累加和為s(i)-s(j-1)。
1. 設定變數sum=0,表示從0位置開始一直加到i位置所有元素的和。設定變數len=0,表示累加和為k的最長子陣列長度。
定義一個HashMap<Int, int>, 中hapmap的 key是 子陣列s(i)的值,value則為該子陣列的最後那個元素的下標,即 i 。
該hashmap的內容形如: <s(i), i>, <s(i+1), (i+1)>。
2. 從左到右開始遍歷,當前元素為arr[i]
1) sum = sum + arr[i],即s(i),在map中檢視是否存在sum-k
如果sum-k存在,從map中取出sum-k對應的value,記為j,得到s(i)-s(j)=k,所以此時arr[j+1, i]的長度即為題目要求的子陣列的長度,如果長度大於len,則更新len。
2) 檢查當前的sum(即s(i))是否在map中,若不存在說明是第一次出現,就把記錄加入到map中。
* 注意 根據arr[j+1, i]的累加和為s(i)-s(j),所以,如果從0開始累加,則j+1>=1。意味著,所有從0開始的子陣列都沒有考慮過,所以,應該從-1位置開始累加,也就是在遍歷之前,先把(0,-1)放進map,也就是如果任何一個數都不加時,累加和為0。
如果不這樣從-1位置開始的話,萬一第0個元素的值就是所求的答案,則就會出誤報找不到這樣的子數字。比如【3,1,2】,K=3。
import java.util.HashMap; import java.util.Map; public class _01_Array_maxLength { public int maxLength(int[] arr, int k) { if (arr == null || arr.length == 0) { return 0; } Map<Integer, Integer> map = newHashMap<Integer, Integer>(); map.put(0, -1); int len = 0; int sum = 0; for (int i = 0; i < arr.length; i++) { sum += arr[i]; if (map.containsKey(sum - k)) { len = Math.max(i - map.get(sum - k), len); } if (!map.containsKey(sum)) { map.put(sum, i); } } return len; } }
補充題目
1. 給定一個無序陣列arr,其中元素可正,可負,可0。求arr所有的子陣列中正數與負數個數相等的最長子陣列長度。
將陣列所有的正數都變為1,負數都變為-1,0不變,然後求累加和為0的最長子陣列長度。
2.給定一個無序陣列arr,其中元素只是1或0。求arr所有的子陣列中0和1個數相等的最長子陣列長度
將陣列所有的0全部變成-1,1不變,然後求累加和為0的最長子陣列長度。