[英]given a set of n integers, return all subsets of k elements that sum to 0
[英]Find all subsets of a set that sum up to n
這是我提出的代碼:
static void findNumbers(int[] list, int index, int current, int goal, String result)
{
if (list.length < index || current>goal)
return;
for (int i = index; i < list.length; i++) {
if (current + list[i] == goal) {
System.out.println(result + " " + String.valueOf(list[i]));
}
else if (current + list[i] < goal) {
findNumbers(list, i + 1, current + list[i], goal, result + " " + String.valueOf(list[i]));
}
}
}
用它來調用:
findNumbers(array, starting_index, current_sum_till_now, target_sum, "");
有人可以幫我弄清楚這段代碼的時間復雜性,我相信它是指數級的。
解決此問題的最佳方法是什么? 它是否正在使用回溯?
有人指出我犯了一個錯誤。 當我應該添加它們時,我正在增加遞歸調用的復雜性。 所以C(N) = C(N-1) + C(N-2) + ...
這同樣適用於C(N-1)
, C(N-2)
等。這意味着復雜度不是' O(N!)
。
這讓我從另一個角度思考算法。 它正在檢查每個可能的子集。 由於存在2^N - 1
可能的子集(不考慮空子集),因此復雜度為O(2^N)
,我認為這是您的原始賭注。
您可以修改您的代碼,使其工作原理是“如果數字是好的 - 添加它;忽略任何條件跳過當前數字”。 在這種情況下,代碼將是:
static void findNumbers(int[] list, int index, int current, int goal, String result)
{
if (list.length <= index || current>goal) // I've added the "=" which is missing in your code.
return;
if (current + list[index] == goal) {
System.out.println(result + " " + String.valueOf(list[i]));
}
else if (current + list[index] < goal) {
findNumbers(list, index + 1, current + list[i], goal, result + " " + String.valueOf(list[i]));
}
findNumbers(list, index + 1, current, goal, result);
}
在這種情況下,復雜度將是O(2^n)
,這對於n=>5
然后是O(n!)
更好。 正如所指出的,如果對數組進行排序,則復雜性會降低。 這意味着您可以將第二個遞歸調用放在else if
因為您將確保后面的所有數字都大於當前list[index]
意味着跳過此值沒有用,因為此調用的所有后續分支都不會生成任何有效的子集。
在這種情況下,最壞的情況是O(2^l)
,其中l
是一個數字的索引,該數字大於你的目標並且在你的數組中,或者如果這樣的數字不存在則為n
。
調用應該是: findNumbers(list,0,0,goal,"")
剛剛指出它比N ^ 2差,實際上它看起來像O(N!)。 您可以保存一些,因為您可以提前退出某些循環,但保存的程度取決於消除可能性的速度。
對於一個更加優化的解決方案,你將要努力,這是遞歸的一個很好的例子,因為任何基於循環的構造都將是可怕的。 您可以通過預先對數據進行排序來節省一些時間,以便首先獲得更大的值,從而更快地達到目標(這將基本上消除列表中立即大於目標的任何內容)。 在消除了太大的條目后,我不確定它是否會直接幫助,因為您仍然需要將所有內容與所有內容進行比較,但它可能會改進處理器分支預測。
這是一種使用動態編程和背包類比的方法: -
按升序對集進行排序
評估子集直到list[i] <= N
解決背包的容量N和物品的價值和重量作為他們的list[i]
如果在最終背包容量N ==最大利潤時,則存在至少一個解決方案子集。
使用成本矩陣回溯所有背包解決方案並獲取所有解決方案子集。
時間復雜度: O(|S|*N + K) |S|- length of set and K is number of subsets.
這是偽多項式時間算法。
注意:問題是NP-hard沒有發現多項式時間算法。
編輯: -從布爾矩陣中回溯解決方案
void retrace(int n,boolean[] solution,int target) {
if(n>=0) {
if(table[target][n-1]) {
solution[n] = false;
retrace(n-1,solution,target);
}
if(table[target-numbers[n]][n-1]) {
solution[n] = true;
retrace(n-1,solution,target-numbers[n]);
}
}
else {
printf("\nsubset:-\n");
for(int i=0;i<solution.length;i++) {
if(solution[i]) {
printf(number[i]+" ");
}
}
}
}
Call : - retrace(numbers.length-1,new boolean[numbers.length],target);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.