簡體   English   中英

查找具有給定總和的數字子集

[英]Finding Subsets of Numbers with a Given Sum

使用遞歸,編寫一個給出整數列表和給定總和的程序,將找到總數是給定總和的數字的所有子集。 計算找到的子集數。 如果不存在子集,則應指明未找到解決方案。 例如,給定列表6,13,3,3並且總和為19,您的程序應該找到兩個解決方案:

6 + 13 = 19
13 + 3 + 3 = 19

將輸入列表中的整數數限制為最多20個整數。 僅接受正整數,並使用0標記列表的結尾。 以下是示例運行:

Enter positive integers terminated with 0: 6 13 3 3 0
Enter the desired sum: 19
Solution 1:6 +13 =19
Solution 2: 13 +3 +3 =19
Found 2 solutions

這是我的代碼,但它只找到一個子集,我想找到所有的子集。 任何幫助?

 public static boolean SubSetSum(int start, int[] nums, int target) {
        if (start >= nums.length) {
            return (target == 0);
        }
        if (SubSetSum(start + 1, nums, target - nums[start])) {

            System.out.println( nums[start] );
            return true;
        }
        if (SubSetSum(start + 1, nums, target)) {

            return true;
        }
        return false;

    }




    public static void main(String[] args) {

        int[] mySet = {4,1,3,2};
        int sum = 5;
        System.out.println("The Goal is : " + sum);

       SubSetSum(0,mySet, sum) ;
    }
}

您的主要問題是:

  • 一旦找到解決方案,馬上就會回來
  • 只考慮從左到右的數字為您的解決方案

您需要做的是考慮解決方案原始列表的所有可能的子列表,例如,對於[A, B, C, D] ,解決方案可能是[A, C, D] 因此,一個好的起點是一些能夠創建列表的所有子列表的代碼。 要做到這一點,您需要有一組列表,您可以聚合所有可能性。 下面是一個通過從原始列表的副本中刪除元素來執行此操作的示例,但有很多方法可以執行此操作:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

class ResursionTest {
    public static void findSubsets(Set<List<Integer>> allSubsets, List<Integer> nums) {
        if (nums.size() == 0) {
            return;
        }

        // add the current list as a possibility
        allSubsets.add(new ArrayList<>(nums));

        // then add a possibility that has one less
        for (int i = 0; i < nums.size(); i++) {
            final List<Integer> subset = new ArrayList<>(nums);
            subset.remove(i);
            findSubsets(allSubsets, subset);
        }
    }


    public static void main(String[] args) {
        final Integer[] array = {4, 1, 3, 2};
        final HashSet<List<Integer>> allSubsets = new HashSet<>();

        findSubsets(allSubsets, Arrays.asList(array));
        System.out.println(allSubsets);
    }
}

如果你運行它,你會看到輸出我們正在查找原始輸入列表[4, 1, 3, 2] 4,1,3,2]的所有子列表。

輸出檢查:

[[3, 2], [1], [4, 3], [2], [3], [1, 2], [4, 3, 2], [1, 3], [4], [4, 1, 2], [4, 1, 3], [4, 1, 3, 2], [4, 1], [1, 3, 2], [4, 2]]

然后剩下的就是只添加加起來所需數量的子列表,而不是添加所有可能性。

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

class ResursionTest {
    public static void findSubsets(Set<List<Integer>> allSubsets, List<Integer> nums, int sum) {
        if (nums.size() == 0) {
            return;
        }

        int currentSum = 0;
        for (Integer num : nums) {
            currentSum += num;
        }

        // does the current list add up to the needed sum?
        if (currentSum == sum) {
            allSubsets.add(new ArrayList<>(nums));
        }

        for (int i = 0; i < nums.size(); i++) {
            final List<Integer> subset = new ArrayList<>(nums);
            subset.remove(i);
            findSubsets(allSubsets, subset, sum);
        }
    }


    public static void main(String[] args) {
        int sum = 5;
        final Integer[] array = {4, 1, 3, 2};
        final HashSet<List<Integer>> allSubsets = new HashSet<>();

        findSubsets(allSubsets, Arrays.asList(array), sum);
        System.out.println(allSubsets);
    }
}

答案檢查:

[[3, 2], [4, 1]]

您仍然可以使用此代碼進行一些優化,我將留給您。

基本問題是您返回了錯誤的信息:您需要找到所有解決方案,但根據您是否成功,您只返回了一個布爾值。 相反,您需要構建一個解決方案列表。

基本情況:

  • 如果target = 0,你就成功了。 打印解決方案並遞增計數器。
  • 否則,如果目標<0,則表示失敗。
  • 否則,如果你沒有剩下的物品,你就失敗了。

遞歸案例:

你對基本想法沒問題:在有和沒有減去當前數字的情況下重復。 但是,您也可以傳遞此分支中使用的數字列表 - 這樣,當您點擊底部時,您可以打印列表。 還有其他方法可以處理這一步驟,但我認為這對您的應用程序來說是最簡單的。 如果您不允許更改SubSetSum的簽名,則將其用作“包裝器”並從那里調用您的實際函數,從空列表開始。

這會讓你感動嗎? 您還可以查看以前有關此問題的幾十個問題。

我的Dp解決方案: -

public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int t = sc.nextInt();
        while(t-->0){
            int n = sc.nextInt();
        int arr[] = new int[n];
        for(int i = 0;i<n;i++){
            arr[i] = sc.nextInt();
        }
        int target = sc.nextInt();
        int dp[] = new int[target+1];
        dp[0] = 1;
        int currSum = 0;
        for(int i = 0;i<n;i++){
            currSum += arr[i];
            for(int j =  Math.min(currSum,target);j>= arr[i];j--){
                dp[j] += dp[j-arr[i]];
            }
        }
        System.out.println(dp[target]);
        }
    }

時間coplx。 O(N *目標)空間complx。 上)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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