3

我正在编写这个函数,我想用整数打印给定列表的所有子列表。这些整数的总和应该等于给定的数字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]and n == 4,那么该方法应该打印[4]and [1 ,3],但它只打印[1, 3]? 我认为 for 循环必须做到这一点,对吗?如果有人让我走上正轨,我将不胜感激。

更新:我赋予该方法的值:

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

更新 2:

我忘了说我希望它是递归的:)

4

4 回答 4

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]
于 2012-03-13T11:54:53.090 回答
2
@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]。那么问题必须是递归的。您当然必须删除重复项:)

于 2012-03-13T11:54:54.560 回答
0

在您的代码的 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从未使用过。所以你重复做同样的事情,我严重怀疑这是你想要做的。

于 2012-03-13T12:10:02.353 回答
0

可能你需要这样做 -

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
        }
    }
}
于 2012-03-13T12:29:01.080 回答