任何人都可以爲下面的問題提出一個簡單的解決方案。最長的子陣列
最長子陣列:查找最長連續子陣列的長度,其中在子陣列中的元素的總和小於或等於到「k」。
輸入是:array
和k
。
實施例:
Array = {1,2,3}, k = 3
輸出:
說明:
子陣列:{1},{2},{3} ,{1,2},{2,3},{1,2,3}
{1,2} => max length = 2; 1 + 2 = 3(< = k);
任何人都可以爲下面的問題提出一個簡單的解決方案。最長的子陣列
最長子陣列:查找最長連續子陣列的長度,其中在子陣列中的元素的總和小於或等於到「k」。
輸入是:array
和k
。
實施例:
Array = {1,2,3}, k = 3
輸出:
說明:
子陣列:{1},{2},{3} ,{1,2},{2,3},{1,2,3}
{1,2} => max length = 2; 1 + 2 = 3(< = k);
一個有效的方法是使用動態規劃,以減少求和操作的次數。例如,如果你總結(1 + 2)= 3,你不想再次求和(1 + 2 + 3)= 6,你只想求和(3 + 3)= 6(前3個已經計算並保存到散列表中)。在此解決方案中,散列映射表示從索引i
到索引j
的和,格式爲<i, <j, sum>>
。所以你從索引i
開始存儲在內部散列表中。請注意,您也可以使用二維數組而不是嵌套哈希映射結構,但對於非常大的數據,在初始化該數組時可能會遇到內存不足異常。
static int maxLength(int[] a, int k) {
Map<Integer, Map<Integer, Long>> map = new HashMap<Integer, Map<Integer, Long>>();
int maxLength = 0;
for(int i = 0; i < a.length - 1; i++) {
Map<Integer, Long> map2 = new HashMap<Integer, Long>();
map2.put(i, (long)a[i]);
map.put(i, map2);
if(a[i] == k) {
maxLength = 1;
}
}
for(int l = 2; l <= a.length; l++) {
long sum = 0;
for(int i = 0; i <= a.length - l; i++) {
int j = i + l - 1;
Map<Integer, Long> map2 = map.get(i);
sum = map2.get(j - 1) + a[j];
map2.put(j, sum);
if(sum <= k) {
if(l > maxLength) {
maxLength = l;
}
}
}
}
return maxLength;
}
最簡單和天真的答案是遍歷你的數組,並找到當前索引處開始的最長的子數組。
int[] a = { 1,2,3,1,1,2,3,1,3 };
int k = 4;
int best_i = 0; // from index
int best_j = 0; // to index, so best length = j - i + 1
int best_sum = 0;
for (int i = 0; i < a.length; i++) { // starting index from beginning to end
int sum = 0;
for (int j = i; j < a.length; j++) { // ending index from current to end
sum += a[j];
if (sum > k) break;
if (j - i > best_j - best_i) { // best length found
best_i = i;
best_j = j;
best_sum = sum;
}
}
}
System.out.println("best length = " + (best_j - best_i + 1) + " (indexes " + best_i + ".." + best_j + "), sum = " + best_sum);
// best length = 3 (indexes 3..5), sum = 4
一種O(n)方法。在高電平:
有2個指針start
和end
,start
是子陣列的開始,end
是端部(排他)。一個int sum
保持子陣列總和。一個int len
保持子數組len。
將兩者都設置爲位置0。
繼續通過移動指針end
:
while (end < arr.length && sum + arr[end] <= k) {
sum += arr[end];
end ++;
}
if ((end - start) > len) {
len = (end-start);
}
哪個會發現你與sum < k
先從最長的子陣列與start
移動start
sum -= arr[start];
start++;
回到1日起至end
通過陣列
的最後一個元素。在結束時,你會發現一些邊緣的情況下給你的最大長度(存儲在len
)
休假處理(例如如果數組中存在值爲> k
的元素。等)
我個人寫了一小段代碼來驗證,這個邏輯應該沒問題。該功能少於25行,自己實現應該不難。鑑於這顯然是某種練習/作業,我不會發布代碼。 –
我剛剛完成了這個挑戰,我採取了類似的方法。但是我不認爲比for循環中的for循環更好。開始指針的工作方式與外部循環一樣。發佈我的代碼。 – Manish
@管理號我猜你錯過了這裏的觀點。它肯定比蠻力(O(n)vs O(n^2))好。再看一看:「結束」指針永遠不會返回。所以這個算法只會將'start'和'end'指針向前移動。當然它有一些假設,比如數組中的值只是正數。 –
這裏我只用於for循環,但我對這個解決方案的複雜性是否O(n)或O(n2)有疑問。看起來像一個for循環,但我不認爲一些操作比蠻力或兩個for循環少。
函數最大長度(A,K){
var maxLen = 0;
var currMaxLen = 0;
var currSum = 0;
var currIndex = 0;
for(index = 0; index < a.length; index++){
currSum = currSum + a[index];
if(currSum <= k){
currMaxLen++;
} else{
//reset
index = currIndex;
currIndex++;
maxLen = Math.max(maxLen, currMaxLen);
currSum = 0;
currMaxLen = 0;
}
}
maxLen = Math.max(maxLen, currMaxLen);
return maxLen;
}
1.它不是Java(正如你所問的那樣)2.它基本上與使用嵌套for循環的強力相同:你重新設置'index = currIndex'(我寧願將它稱爲'end'和'start'),當你增加currIndex時,它只能讓你從一個非常天真的蠻力實現中循環。(當你遇到通過數組尾部的子數組時,會提前中斷) –
所以,極端情況:如果你有一個數組'[0,0,0,0,0,0,0,0,0,100]'和你想找到'k = 1',你應該很明顯的發現它是一個'O(n^2)'算法 –
問題陳述是不明確。你想找到小於或等於'k'的最大可能值?這聽起來太簡單了,因爲它本身就是'k'。 – Hiren
您是否想要找到_length_是_k_的子數組,或_sum_是_k_的子數組? –
不好意思。現在編輯這個問題。 – sam