【问题标题】:List of subsets of which their elements add up to n using recursion使用递归将其元素加起来为 n 的子集列表
【发布时间】:2012-03-13 11:42:21
【问题描述】:

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

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

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

更新 2:

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

【问题讨论】:

标签: java recursion backtracking subset-sum


【解决方案1】:

当您看到总和为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]

【讨论】:

  • 我不明白这样子列表的长度怎么变成0了?当数字的总和为 n 时,它必须停止(每次 = nr 个可能的子集)。对吗?
  • 除了停止条件之外,您的代码还有更多错误。错误的退出标准隐藏了更多问题,甚至无法编译(ArrayList 没有sum() 方法)。
【解决方案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]。那么问题必须是递归的。当然,您必须删除重复项:)

【讨论】:

  • 忘了说我希望它是递归的。更新了我的问题。
  • 顺便说一句,这似乎完全是从其他网站复制的。除非您是该页面的所有者。
  • 代码是我写的。算法很简单,所以我想你会找到类似的解决方案。
  • 我根据维基百科重写了。问题在于集合。您必须删除重复以提高性能。代码是我的 :)
【解决方案3】:

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

【讨论】:

  • 我想在我的情况下for循环应该运行两次吧?子列表的数量?谢谢顺便说一句,会看看它:)
【解决方案4】:

你可能需要这样做——

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
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-10-25
    • 2018-01-17
    • 1970-01-01
    • 1970-01-01
    • 2020-01-21
    • 2016-01-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多