簡體   English   中英

使用遞歸將其元素加到n的子集列表

[英]List of subsets of which their elements add up to n using recursion

我正在寫這個函數,我想用整數打印給定列表的所有子列表。 這些整數的總和應該等於給定的數字n 還有一個幫助變量i ,它以值0開頭。列表和每個子列表都是一個ArrayList 所以這個方法現在看起來像這樣:

public static void printSublists(ArrayList numbers, ArrayList sublist, int n,
            int i) {

        if (sublist.sum() == n) {
            System.out.println(sublist.toString());
        } 
        else {
            for (int j = 0; j < numbers.size(); j++) {
                sublist.add(numbers.get(i));
                printSublists(numbers, sublist, n, i + 1);
                sublist.remove(numbers.get(i));
            }
        }
    }

當然我已經有方法sum() 該方法現在這樣做:讓numbers = [1, 3 , 4] 1,3,4 numbers = [1, 3 , 4]n == 4 ,然后該方法應該打印[4][1 ,3] ,但它只打印[1, 3] 我認為for-loop必須正確嗎? 如果有人讓我走上正軌,我將不勝感激。

更新:我給方法的值:

numbers = [1, 3, 4]
n = 4
i = 0
sublist = []

更新2:

我忘了說我希望它是遞歸的:)

當您看到第一個子列表的總和為n時,遞歸會停止。 問題不是(僅)循環而是退出標准。 當子列表長度為0時,您的遞歸函數應該停止。


在這里,我剛剛為您的問題編寫了一個有效的遞歸解決方案。 這是不同的,但我無法解決你的問題。 當你從一個空的子列表開始時,我選擇使用完整列表初始化遞歸,並將其划分為較小的子列表。 這會創建一個樹狀結構:

                        [1234]
                     [123]  [234]
                   [12] [23]   [34]
                  [1][2]  [3]    [4]

我們立即看到,我們必須“向右”走,直到我們到達第一片葉子( 1 ),然后我們只走“左”。 這樣我們只訪問所有子列表一次。

這是用Java編寫的想法:

public static void main (String[] args) {
  ArrayList<Integer> list = new ArrayList<Integer>();
  list.add(1);
  list.add(3);
  list.add(4);
  list.add(0);
  printSublists(list, list, 4, true, 0);
}

public static void printSublists(List<Integer> numbers, List<Integer> sublist, int n, boolean walkRight, int level) {

  // the test
  if (sum(sublist) == n)
     System.out.println(sublist);

  // the exit criteia (leaf reached)
  if (sublist.size() == 1)
     return;

  // visit the right sublist
  if (walkRight) 
    printSublists(numbers, sublist.subList(0, sublist.size()-1), n, walkRight, level+1);

  // we only walk the right path once
  walkRight = false;

  // visit the left sublist
  printSublists(numbers, sublist.subList(1, sublist.size()), n, walkRight, level+1);
}

那是輸出:

[1, 3]
[4]
[4, 0]
@Test
public void test() {
    printSublists(new HashSet<Integer>(Arrays.asList(2, 3, 4, 1, 2)), new HashSet<Integer>(), 4);
}

private void printSublists(Set<Integer> numbers, Set<Integer> subList, int expected) {

    for (Integer element : numbers) {
        subList.add(element);
        if (sum(subList) == expected) {
            System.out.println("result =" + subList);
        }
        Set<Integer> listWithoutElement = withoutElement(numbers, element);
        printSublists(listWithoutElement, subList, expected);
        subList.remove(element);

    }
}

private Set<Integer> withoutElement(Set<Integer> numbers, Integer element) {
    Set<Integer> newList = new HashSet<Integer>(numbers);
    newList.remove(element);
    return newList;
}

private int sum(Collection<Integer> sublist) {
    int sum = 0;
    for (Integer e : sublist) {
        sum += e;
    }
    return sum;

}

這是你的解決方案。 這個問題應該是集合,而不是列表。

如果你設置[2,3,4,1,2] ,解決方案應該是[3,1] [4] [2,2] 然后問題必須是遞歸的。 你必須刪除重復當然:)

在你的代碼的for循環中:

        for (int j = 0; j < numbers.size(); j++) {
            sublist.add(numbers.get(i));
            printSublists(numbers, sublist, n, i + 1);
            sublist.remove(numbers.get(i));
        }

從不使用變量j 所以你反復做同樣的事情,我嚴重懷疑你想做什么。

可能你需要這樣做 -

public static void printSublists(ArrayList numbers, ArrayList sublist, int n,
        int i) {

    if (sublist.sum() == n) {
        System.out.println(sublist.toString());
        sublist.removeAll(sublist);//added remove all here
    } 
    else {
        //for (int j = 0; j < numbers.size(); j++) {//commented this line
        while(i<number.size()){//need while loop
            sublist.add(numbers.get(i));
            printSublists(numbers, sublist, n, ++i);//i+1 changed to ++i
            //sublist.remove(numbers.get(i));// commented here
        }
    }
}

暫無
暫無

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

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