簡體   English   中英

查找總計為n的集合的所有子集

[英]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!)。 您可以保存一些,因為您可以提前退出某些循環,但保存的程度取決於消除可能性的速度。

對於一個更加優化的解決方案,你將要努力,這是遞歸的一個很好的例子,因為任何基於循環的構造都將是可怕的。 您可以通過預先對數據進行排序來節省一些時間,以便首先獲得更大的值,從而更快地達到目標(這將基本上消除列表中立即大於目標的任何內容)。 在消除了太大的條目后,我不確定它是否會直接幫助,因為您仍然需要將所有內容與所有內容進行比較,但它可能會改進處理器分支預測。

這是一種使用動態編程和背包類比的方法: -

  1. 按升序對集進行排序

  2. 評估子集直到list[i] <= N

  3. 解決背包的容量N和物品的價值和重量作為他們的list[i]

  4. 如果在最終背包容量N ==最大利潤時,則存在至少一個解決方案子集。

  5. 使用成本矩陣回溯所有背包解決方案並獲取所有解決方案子集。

時間復雜度: 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM