Java输出回复如此之慢

时间:2017-06-18 05:40:34

标签: java

我正在做一个关于攀爬墙壁的蜗牛的练习,我必须计算到达顶部所需的manys天数,我已经完成了我的算法并且它给了我预期的输出但它需要在一个输入的情况下,基本上代码必须做的是给出NMTN =他一天爬的男子米M =他在夜间坠落的男子米数T =墙的长度这是我的代码任何帮助将是有用的这是我的代码PD它已经工作,但它太慢

       int distance=0;

       int[] up = { 2, 5 ,100};
       int[] down= { 1,1 ,99};
       int[] Top = {5,6 ,1000000000};
       int days = 0;
       for (int i = 0; i < up.length; )
       {
           distance += up[i];
           if (Top[i] <= distance)
           {
               days++;
               System.out.println(days);
                i++;
               days = 0;
               distance = 0;

           }
           else
           {
               distance -= down[i];
               days++;
           }

       }   

输出是下一个:案例1:4 案例2:2 案例3:999999901

2 个答案:

答案 0 :(得分:3)

您的代码可以重构以简化它。这就是Wikipedia描述重构的方式:

  

代码重构是重构现有计算机代码的过程 - 更改因子分析 - 而不更改其外部行为。重构改进了软件的非功能属性。 优势包括提高代码可读性和降低复杂性;这些可以提高源代码的可维护性,并创建更具表现力的内部架构或对象模型,以提高可扩展性。 通常,重构会应用一系列标准化的基本微重构 ,每个都是(通常)计算机程序源代码中的微小变化,或者保留了软件,或至少不修改其对功能要求的符合性。

所以我们将应用一组微重构。

首先,可以翻转else子句中的两个语句。

} else {
    days++;   // Statement moved up
    distance -= down[i];
}

执行此操作时,if块和else块都以days++;开头,因此可以移到外面。

for (int i = 0; i < up.length;) {
    distance += up[i];
    days++;   // Statement moved outside
    if (Top[i] <= distance) {
        System.out.println(days);
        i++;
        days = 0;
        distance = 0;
    } else {
        distance -= down[i];
    }
}

由于for循环不会修改i,因此只要循环内的代码不会更改i,它就会像永久循环一样运行。因此,当我们更改i时,我们可以添加一个永久循环并突破它。结果是没有任何改变,但它准备下一组重构。

for (int i = 0; i < up.length;) {
    for (;;) {   // Forever-loop
        distance += up[i];
        days++;
        if (Top[i] <= distance) {
            System.out.println(days);
            i++;
            days = 0;
            distance = 0;
            break;   // Break out, since we changed i
        } else {
            distance -= down[i];
        }
    }
}

由于break语句是退出forever循环的唯一方法,因此我们可以将break之前的代码移动到循环之外(即之后)。

int distance = 0;
int days = 0;
for (int i = 0; i < up.length;) {
    for (;;) {
        distance += up[i];
        days++;
        if (Top[i] <= distance) {
            break;
        } else {
            distance -= down[i];
        }
    }
    System.out.println(days);   // Moved outside forever-loop
    i++;                        // Moved outside forever-loop
    days = 0;                   // Moved outside forever-loop
    distance = 0;               // Moved outside forever-loop
}

由于daysdistance在外部循环之前被初始化为0,并且在循环结束时重新初始化为0,因此我们可以在反而开始循环,然后我们可以在那里声明它们。我们还可以将i++移至for循环。

for (int i = 0; i < up.length; i++) {   // i++ moved here
    int distance = 0;   // Moved to top of loop and declared here
    int days = 0;       // Moved to top of loop and declared here
    for (;;) {
        distance += up[i];
        days++;
        if (Top[i] <= distance) {
            break;
        } else {
            distance -= down[i];
        }
    }
    System.out.println(days);
}

我们现在将对永久循环内增加distancedays的两个语句执行相反的操作,即在循环之前和循环结束时执行这两个语句

for (int i = 0; i < up.length; i++) {
    int distance = 0;
    int days = 0;
    distance += up[i];   // Moved here
    days++;              // Moved here
    for (;;) {
        if (Top[i] <= distance) {
            break;
        } else {
            distance -= down[i];
        }
        distance += up[i];   // Also moved here
        days++;              // Also moved here
    }
    System.out.println(days);
}

distancedays的初始化可以与永久循环之前的递增相结合。此外,由于break退出循环,因此不再需要else

for (int i = 0; i < up.length; i++) {
    int distance = up[i];   // Combined =0 with +=up[i]
    int days = 1;           // Combined =0 with ++
    for (;;) {
        if (Top[i] <= distance)
            break;
        distance -= down[i];   // else clause eliminated
        distance += up[i];
        days++;
    }
    System.out.println(days);
}

distance仅在forever循环中使用,因此我们可以将声明移动到循环中。 distance的更新可以移动到永久循环的第3部分。 if语句位于forever循环的顶部,因此它可以成为循环条件,将forever循环更改为常规for循环。

for (int i = 0; i < up.length; i++) {
    int days = 1;
    for (int distance = up[i]; distance < Top[i]; distance += up[i] - down[i]) {
        days++;
    }
    System.out.println(days);
}

看看你的代码现在有多简单,我们从未改变过代码的逻辑。我们只是移动它,即重构它

你的性能问题是由于内循环在第三次使用情况下必须迭代近十亿次,但现在我们可以看到一个简单的for循环,我们实际上可以计算迭代次数。

要构建该公式,请考虑正常循环。

for (int value = start; value < stop; value += step)

迭代次数是多少次?在step到达x之前,必须总共valuestop次,这意味着x = (stop - start) / step

如果stop - start不是step的完全倍数,我们需要确保始终向上舍入,因此value将为>= stop。使用整数数学,您可以通过在分割前添加step - 1来实现,因为整数除法会截断结果,从而产生以下公式:x = (stop - start + step - 1) / step

将它应用于我们的循环,我们得到:

x = (stop - start + step - 1) / step
x = (Top[i] - up[i] + (up[i] - down[i]) - 1) / (up[i] - down[i])
x = (Top[i] - down[i] - 1) / (up[i] - down[i])

days = 1 + x
days = 1 + (Top[i] - down[i] - 1) / (up[i] - down[i])

由于不再需要将结果分配给变量days,因此您的代码将变为:

int[] up = { 2, 5, 100 };
int[] down = { 1, 1, 99 };
int[] Top = { 5, 6, 1000000000 };
for (int i = 0; i < up.length; i++)
    System.out.println(1 + (Top[i] - down[i] - 1) / (up[i] - down[i]));

输出

4
2
999999901

立即计算结果。没有延误。

答案 1 :(得分:0)

您可以使用一些小数学来得出一个封闭的公式:

Math.ceil(((double)top - down) / (up - down))