代码效率和准确性

时间:2016-12-15 04:02:45

标签: c# linq collections processing-efficiency

我正在尝试解决代码大战中的问题,所提供的单元测试完全没有意义......

问题如下,听起来非常简单,可以在5分钟内完成工作

Consider a sequence u where u is defined as follows:

The number u(0) = 1 is the first one in u.
For each x in u, then y = 2 * x + 1 and z = 3 * x + 1 must be in u too.
There are no other numbers in u.
Ex: u = [1, 3, 4, 7, 9, 10, 13, 15, 19, 21, 22, 27, ...]

1 gives 3 and 4, then 3 gives 7 and 10, 4 gives 9 and 13, then 7 gives 15 and 22 and so on...

Task:

Given parameter n the function dbl_linear (or dblLinear...) returns the element u(n) of the ordered (with <) sequence u.

Example:

dbl_linear(10) should return 22

起初我使用带有linq查询的一个sortedset,因为我并不真正关心效率,我很快就知道这个操作必须计算到n在12秒内可以等于~100000的范围。

所以这种憎恶诞生了,然后一次又一次地被屠杀,因为for循环会因某种原因产生问题。然后它被“升级”为一个while循环,它给出了更多的单元测试(4 - > 8)。

public class DoubleLinear {
    public static int DblLinear(int n) {
        ListSet<int> table = new ListSet<int> {1};
        for (int i = 0; i < n; i++) {
            table.Put(Y(table[i]));
            table.Put(Z(table[i]));
        }
        table.Sort();
        return table[n];
    }

    private static int Y(int y) {
        return 2 * y + 1;
    }

    private static int Z(int z) {
        return 3 * z + 1;
    }

}

public class ListSet<T> : List<T> {
    public void Put(T item) {
        if (!this.Contains(item))
            this.Add(item);
    }

}

使用此代码仍然无法计算超过n = 75000,但最多可以进行8次测试。

我已经检查过其他人是否通过了这个,他们有。但是,我无法检查他们写的东西,以便从中学习。

任何人都可以提供有关此处可能出现的错误的见解吗?我确定答案显而易见,而且我很愚蠢。

也是这样使用自定义列表一个坏主意?有更好的方法吗?

1 个答案:

答案 0 :(得分:1)

ListSet对于排序很慢,并且在构建集合时不断获得内存重新分配。我首先要先分配完整大小的表格,但老实说,我也会告诉你使用你需要的大小数量的准系统最适合性能。

如果您知道您需要n = 75,000+,请分配该大小的ListSet(或ARRAY!)。如果单元测试开始带你进入平流层,我们可以讨论一种二进制分割技术,但这有点涉及并且逻辑上难以构建。

我没有看到任何逻辑错误的代码。它产生的数字在我站立的地方是正确的。

编辑:因为你知道3n + 1&gt; 2n + 1,你只需要保持6个值:

Target index in u
Current index in u
Current x for y
Current x for z
Current val for y
Current val for z
public static int DblLinear(int target) {
    uint index = 1;
    uint ind_y = 1;
    uint ind_z = 1;
    uint val_y = 3;
    uint val_z = 4;

    if(target < 1)
        return 1;

    while(index < target) {
        if(val_y < val_z) {
            ind_y++;
            val_y = 2*ind_y + 1;
        } else {
            ind_z++;
            val_z = 3*ind_z + 1;
        }
        index++;
    }

    return (val_y < val_z) ? val_y : val_z;

}

如果要将分支扩展为2个条件,或者在超出目标索引时实现后退循环,则可以修改val_y if if为while循环(更有效的关键路径)。

没有内存分配肯定会加快你的计算速度,即使是人们想要(错误地)在这种容易预测的情况下对分支预测感到不适。

另外,您是否在Visual Studio项目中启用了优化?如果您提交的是二进制文件而不是代码文件,那么这也可以节省相当多的时间。