Java ArrayList 克隆改进的运行时间

4
这是问题:https://leetcode.com/problems/combinations/ 这是我的解决方案1:
   public class Solution {

    public List<List<Integer>> combine(int n, int k){
        List<List<Integer>> result = new ArrayList<List<Integer>>();
        combine(n, k, 1, result, new ArrayList<Integer>());
        return result;
    }

    public void combine(int n, int k , int start, List<List<Integer>> result, ArrayList<Integer> l){
        if(k == 0){
            result.add(l);
            return;
        }
        for(int i = start; i <= n; ++i){

            l.add(i);
            combine(n, k - 1, i + 1, result, l);
        }
    }


    }

结果:小规模测试用例已通过。但大规模测试用例超时。

提交结果:时间限制已超出 上一次执行的输入:10,5

解决方案2:

public class Solution {

public List<List<Integer>> combine(int n, int k){
    List<List<Integer>> result = new ArrayList<List<Integer>>();
    combine(n, k, 1, result, new ArrayList<Integer>());
    return result;
}

public void combine(int n, int k , int start, List<List<Integer>> result, ArrayList<Integer> l){
    if(k == 0){
        result.add(l);
        return;
    }
    for(int i = start; i <= n; ++i){
        ArrayList<Integer> a = (ArrayList<Integer>) l.clone();
        a.add(i);
        combine(n, k - 1, i + 1, result, a);
    }
}


}

所有测试用例均已通过。

主要区别在于列表的克隆。 但为什么? 方案A是错误的还是只是慢? 为什么在这里使用克隆更快? 真的很困惑。


如果您不打算修改解决方案,使用共享链表可能会更好。 - Willem Van Onsem
1个回答

3
第一个解决方案确实是错误的。尝试调用combine(5,3),并将其发送到System.out,你会看到第一个输出的结果是:
[[1, 2, 3, 4, 5, 3, 4, 5, 4, 5, 5, 2, 3, 4, 5, 4, 5, 5, 3, 4, 5, 5, 4, 5, 5], [1, 2, 3, 4, 5, 3, 4, 5, 4, 5, 5, 2, 3, 4, 5, 4, 5, 5, 3, 4, 5, 5, 4, 5, 5], [1, 2, 3, 4, 5, 3, 4, 5, 4, 5, 5, 2, 3, 4, 5, 4, 5, 5, 3, 4, 5, 5, 4, 5, 5], [1, 2, 3, 4, 5, 3, 4, 5, 4, 5, 5, 2, 3, 4, 5, 4, 5, 5, 3, 4, 5, 5, 4, 5, 5], [1, 2, 3, 4, 5, 3, 4, 5, 4, 5, 5, 2, 3, 4, 5, 4, 5, 5, 3, 4, 5, 5, 4, 5, 5], [1, 2, 3, 4, 5, 3, 4, 5, 4, 5, 5, 2, 3, 4, 5, 4, 5, 5, 3, 4, 5, 5, 4, 5, 5], [1, 2, 3, 4, 5, 3, 4, 5, 4, 5, 5, 2, 3, 4, 5, 4, 5, 5, 3, 4, 5, 5, 4, 5, 5], [1, 2, 3, 4, 5, 3, 4, 5, 4, 5, 5, 2, 3, 4, 5, 4, 5, 5, 3, 4, 5, 5, 4, 5, 5], [1, 2, 3, 4, 5, 3, 4, 5, 4, 5, 5, 2, 3, 4, 5, 4, 5, 5, 3, 4, 5, 5, 4, 5, 5], [1, 2, 3, 4, 5, 3, 4, 5, 4, 5, 5, 2, 3, 4, 5, 4, 5, 5, 3, 4, 5, 5, 4, 5, 5]]
你会注意到每个索引位置上的列表是相同的 - 你确实需要每次创建一个新的数组。对于第二个正确的解决方案,输出是:

[[1, 2, 3], [1, 2, 4], [1, 2, 5], [1, 3, 4], [1, 3, 5], [1, 4, 5], [2, 3, 4], [2, 3, 5], [2, 4, 5], [3, 4, 5]]

这意味着第一个解决方案较慢,因为每次都将数字添加到越来越大的列表中。对于更高的n和k值,该列表可能非常大,并且在需要扩展时复制 ArrayList 的后备数组成为非常昂贵的操作 - 比复制/创建许多小列表要昂贵得多。

他该如何修复第一个解决方案?他做错了什么?谢谢。 - Unheilig
1
@Unheilig 解决方法是每次创建一个新的数组,这就是他在第二个解决方案中所做的。 - mk.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接