Java递归通过ArrayList中的引用

时间:2018-07-01 06:12:42

标签: java algorithm recursion arraylist

我正在研究一个问题,以找出给定列表中哪些整数的所有组合都可以累加为给定数字。

public class SumProblem {

/*
 * Input 2-2-3-7
 * Output 2+2+3 and 7
 */

public static ArrayList<ArrayList<Integer>>  find(ArrayList<Integer> input, int requiredSum) {
    ArrayList<ArrayList<Integer>> result = new ArrayList<>();
    find(result, requiredSum, 0, new ArrayList<>(), 0, input);
    return result;
}

public static void find(ArrayList<ArrayList<Integer>> result , int requiredSum , int currentSum,  ArrayList<Integer> partialResult, int i, ArrayList<Integer> input) {

    if (currentSum == requiredSum ) {
        ArrayList<Integer> temp = new ArrayList<>();
        temp = (ArrayList<Integer>) partialResult.clone();
        result.add(temp);
        return;
    }

    if (i >= input.size()) {
        return;
    }
    find(result, requiredSum, currentSum , partialResult, i +1, input );
    partialResult.add(input.get(i));
    find(result, requiredSum, currentSum + input.get(i) , partialResult, i +1, input );
}

public static void main(String[] args) {

    ArrayList<Integer> input = new ArrayList<>();
    input.add(2);
    input.add(1);
    input.add(3);
    ArrayList<ArrayList<Integer>>  output = find(input, 3);
    System.out.println(output.toString());
}

}

我在下面编写了代码。 我面临一个问题。在下面的代码行中,即使我创建了新的ArrayList对象并将其分配给partialResult,它也会将我遍历的所有数字相加。

partialResult.add(input.get(i));

有人可以建议解决方案吗?

1 个答案:

答案 0 :(得分:1)

在此动态编程解决方案中,您有两次递归调用。一个应该不包含当前值,另一个应该包含。

您需要制作防御性的partialResult副本,否则两个递归调用都将引用 相同 列表。列表是可变对象。如果两个调用都引用了相同的列表对象,则在任何地方向其中添加内容时,两个都将看到修改后的列表。

创建列表的防御性副本的最简单方法是编写:

new ArrayList<>(partialResult)

这是该程序的有效版本:

导入java.util。*;

public class SumProblem {
    public static List<List<Integer>> find(List<Integer> input, int requiredSum) {
        List<List<Integer>> result = new ArrayList<>();
        find(result, requiredSum, 0, new ArrayList<>(), 0, input);
        return result;
    }

    public static void find(List<List<Integer>> result, int requiredSum, int currentSum,
            List<Integer> partialResult, int i, List<Integer> input) {
        if (currentSum == requiredSum) {
            result.add(new ArrayList<>(partialResult)); // add a copy of the list
            return;
        }

        if (i >= input.size()) {
            return;
        }
        // make defensive copies in the recursive calls
        find(result, requiredSum, currentSum, new ArrayList<>(partialResult), i + 1, input);
        partialResult.add(input.get(i));
        find(result, requiredSum, currentSum + input.get(i), new ArrayList<>(partialResult), i + 1, input);
    }

    public static void main(String[] args) {
        List<Integer> input = List.of(2, 8, 2, 3, 4);
        List<List<Integer>> output = find(input, 7);
        System.out.println(output);
    }
}

输出:

  

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

我进行了其他一些更改:

  • 使用List<Integer>List<List<Integer>>作为类型(接口的代码)
  • 使用List.of()创建输入列表(已在Java 9中添加)
  • 不要在传递给toString()的对象上调用println-不需要