简体   繁体   English

Java递归通过ArrayList中的引用

[英]Java Recursion Pass by Reference in ArrayList

I am working on a problem to find which all combinations of integer in a given list can sum up to a given number. 我正在研究一个问题,以查找给定列表中整数的所有组合可以总计为给定数字。

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());
}

} }

I have written code below. 我在下面编写了代码。 I am facing one problem. 我面临一个问题。 In the below line of code, it is adding up all the numbers i traverse even if i create new ArrayList object and assign it to partialResult. 在下面的代码行中,即使我创建新的ArrayList对象并将其分配给partialResult,它也会将我遍历的所有数字相加。

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

Could anyone suggest the solution ? 有人可以建议解决方案吗?

You have two recursive calls in this dynamic programming solution to the problem. 在此问题的动态编程解决方案中,您有两个递归调用。 One is supposed to not include the current value in the result, the other does. 一个应该不包含当前值,另一个应该包含。

You need to make a defensive copy of partialResult, otherwise both recursive calls are going to have a reference to the same list. 您需要制作防御性的partialResult副本,否则两个递归调用都将引用同一列表。 A list is a mutable object. 列表是可变对象。 If both calls get a reference to the same list object, then when you add something to it anywhere , both of them will see the modified list. 如果两个调用都引用了相同的列表对象,则在任何地方向其添加内容时,两个都将看到修改后的列表。

The easiest way to make a defensive copy of a list is just to write: 制作列表的防御性副本的最简单方法是编写:

new ArrayList<>(partialResult)

Here is a working version of the program: 这是程序的工作版本:

import java.util.*; 导入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);
    }
}

Output: 输出:

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

I've made a few other changes: 我进行了其他一些更改:

  • Use List<Integer> and List<List<Integer>> as the types (code to the interface) 使用List<Integer>List<List<Integer>>作为类型(接口的代码)
  • Use List.of() to create the input list (added in Java 9) 使用List.of()创建输入列表(在Java 9中添加)
  • Don't call toString() on objects passed to println — it's unneeded 不要在传递给println对象上调用toString() -不需要

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM