繁体   English   中英

迭代和递归解决方案的时间复杂度

[英]Time complexity on iterative and recursive solution

我正在尝试解决以下问题: 编程问题

我觉得我已经给了很多想法,尝试了很多东西。 我设法解决了这个问题,并产生了正确的值,但是问题是时间效率不够高。 它完成了Kattis测试中的2个,但由于超过了1秒的时间限制而未能完成3个测试。 恐怕我没有办法看到他们测试的输入是什么。

我从一个递归解决方案开始,并完成了这一过程。 但是后来我意识到这不够省时,因此我尝试改用迭代解决方案。

我从读取输入开始,然后将其添加到ArrayList中。 然后,我将目标为1000的以下方法调用。

public static int getCorrectWeight(List<Integer> platesArr, int target) {
    /* Creates two lists, one for storing completed values after each iteration,
    one for storing new values during iteration. */
    List<Integer> vals = new ArrayList<>();
    List<Integer> newVals = new ArrayList<>();

    // Inserts 0 as a first value so that we can start the first iteration.
    int best = 0;
    vals.add(best);

    for(int i=0; i < platesArr.size(); i++) {
        for(int j=0; j < vals.size(); j++) {
            int newVal = vals.get(j) + platesArr.get(i);
            if (newVal <= target) {
                newVals.add(newVal);
                if (newVal > best) {
                    best = newVal;
                }
            } else if ((Math.abs(target-newVal) < Math.abs(target-best)) || (Math.abs(target-newVal) == Math.abs(target-best) && newVal > best)) {
                best = newVal;
            }
        }
        vals.addAll(newVals);
    }
    return best;
}

我的问题是,对于减少大量数据,我是否可以通过某种方法来减少时间复杂度?

主要的问题是大小valsnewVals可以非常快速地增长,因为每个迭代可以增加一倍它们的大小。 您只需要存储1000个左右的值即可管理。 您在限制值,但是因为它们存储在ArrayList ,所以最终会有很多重复的值。

相反,如果您使用了HashSet ,那么它将HashSet提高效率。

您仅需要存储大小为2001(0到2000)的DP表,让dp[i]表示是否可以形成i kg的权重。 如果权重超出数组范围,请忽略它。 例如:

dp[0] = 1;      
for (int i = 0; i < values.size();  i++){
    for (int j = 2000; j >= values[i]; j--){  
        dp[j] = max(dp[j],dp[j-values[i]);
    }
}

在这里, values是存储所有原始权重的位置。 dp[0]外,所有dp值均应设置为0。

然后,检查是否有可能达到1000。 如果不是,请检查999和1001,依此类推。 这应该以O(1000n + 2000)时间运行,因为n最多为1000,所以应该及时运行。

顺便说一句,这是一种改进的背包算法,您可能需要查找其他一些变体。

如果您对这种类型的问题过于笼统,则可能会认为您必须检查所有可能的输入组合(每个权重都可以包括或排除),为您提供2 n种组合以测试是否有n种输入。 但是,这不是重点。 相反,这里的关键是所有权重都是整数,目标是1000。

让我们先检查极端情况,因为这限制了搜索空间。

如果所有权重均> = 1000,则选择最小的权重。

如果至少有一个权重<1000,则总是比任何权重> = 2000更好,因此出于组合目的,您可以忽略任何权重> = 1000。

然后,应用动态编程。 保留前k个输入的所有组合的集合(从其他海报中获得HashSet作为建议,但BitSet更好,因为其最大值很小),并通过将所有先前的解决方案与k + 1组合来增加k的输入。

考虑完所有可能性后,只需搜索位向量以获得最佳响应。

static int count() {
    int[] weights = new int[]{900, 500, 498, 4};

    // Check for corner case to limit search later
    int min = Integer.MAX_VALUE;
    for (int weight : weights) min = Math.min(min, weight);
    if (min >= 1000) {
        return min;
    }        
    // Get all interesting combinations
    BitSet combos = new BitSet();
    for (int weight : weights) {  
        if (weight < 1000) {
            for (int t = combos.previousSetBit(2000 - weight) ; t >= 0; t = combos.previousSetBit(t-1)) {
                combos.set(weight + t);
            }
            combos.set(weight);
        }
    }
    // Pick best combo
    for (int distance = 0; distance <= 1000; distance++) {
        if (combos.get(1000 + distance)) {
            return 1000 + distance;
        }
        if (combos.get(1000 - distance)) {
            return 1000 - distance;
        }
    }
    return 0;
}

暂无
暂无

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

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