【问题标题】:How can I optimize This Code Into Lesser Line of Code如何将此代码优化为较小的代码行
【发布时间】:2020-02-13 14:36:28
【问题描述】:

如何优化这段代码。

我想减少代码行数。

public class CoolDude {
    public static void main(String[] args) {
        for(int i = 100; i <= 500; ++i) {
            if(i%5 == 0 && i%11 == 0) {
                System.out.print("Cool Dude- ");
                System.out.print(i + "\n");
            } else if (i%5 == 0) {
                System.out.print("Cool - ");
                System.out.print(i + "\n");
            } else if (i%11 == 0) {
                System.out.print("Dude - ");
                System.out.print(i + "\n");
            }
        }
    }

}

有什么办法吗?

【问题讨论】:

  • 每个分支只需要调用一次System.out,可以使用println避免每次都需要+ "\n"
  • 这是 Java,因此您可以删除所有换行符并将整个内容放在一行中。但我认为这不是你真正想问的。
  • 不同的语言,但相关:stackoverflow.com/questions/9461446/…。注意:在最初的“FizzBu​​zz”面试问题中,在第一次测试中,“Dude”和“-”之间有一个空格。
  • 这不是一个 FizzBu​​zz 问题,而是一个非常接近的问题:对于不是两个除数的倍数的数字,没有输出。它可以以 FizzBu​​zz 无法优化的方式进行优化。

标签: java


【解决方案1】:

虽然Stephen M Irving's answer 非常准确并纠正了您在问题中发现的所有信念,但它仍然可以回答您的问题,并尽量减少陈述的数量。

public class CoolDude {
  public static void main(String[] args) {
    for (int i = 100; i <= 500; i++)
      if (i % 5 == 0 || i % 11 == 0) // This is the condition where we decide to print something
        System.out.printf("%s%s- %d%n", i % 5 == 0 ? "Cool " : "", i % 11 == 0 ? "Dude " : "", i);
  }
}

但是,此代码重复了最昂贵的部分之一:模数。此外,此解决方案不可读

当尝试找出解决方案很有用时,尝试几个 KPI,然后找到最佳优化。在这种情况下,您想优化行数,这绝对不是您在上面看到的最好的。如果有任何事情首先尝试获得一个可行的解决方案,然后是一个可读的解决方案,最后是一个优化的解决方案,您可以在其中记录为什么要优化它以保持可读性。

例如,这是我能想到的最优化的版本。它肯定包含更多行,但也肯定更快,因为我跳过所有无效数字并且从不做模(整个程序只有两个除法和两个乘法)。

public class CoolDude {
  public static void main(String[] args) {
    final int min = 100;
    final int max = 500;
    for (int i5 = nextMultiple(min, 5), i11 = nextMultiple(min, 11); i5 <= max || i11 <= max; ) {
      if (i5 < i11) {
        System.out.printf("Cool - %d%n", i5);
        i5 += 5;
      } else if (i11 < i5) {
        System.out.printf("Dude - %d%n", i11);
        i11 += 11;
      } else { // i5 == i11
        System.out.printf("Cool Dude - %d%n", i5);
        i5 += 5;
        i11 += 11;
      }
    }
  }
  static int nextMultiple(int number, int divisor) {
    int roundToLower = (number - 1) / divisor * divisor;
    return roundToLower + divisor;
  }
}

【讨论】:

  • 我一直在努力解决如何通过 5、11 和 55 进行迭代计数,但我很难弄清楚如何将数字保持在正确的顺序。干得好!
【解决方案2】:

您可以重组您的决策树,以便只需要对循环中的数字进行 2 次检查(每次检查 1 次操作和 1 次比较)。目前,您的决策树在最佳情况下需要 2 次操作和 2 次比较(i 可被 5 和 11 整除),在最坏情况下需要 4 次操作和 4 次比较(i 不能被 5 或 11 整除) ,但我们可以将其减少为始终只有 2 次比较和 2 次操作,这将产生更高性能的循环。这样,i 只针对每个数字对 5 和 11 的可除性进行了一次测试,因此无论循环的哪个阶段都只需要进行 2 次操作和 2 次比较。这是您在尝试优化循环时应该考虑的优化类型。

我还让您的print 方法调用了printf 调用,从而将两个打印语句减少为1。这是一个printf cheat sheet,如果您不熟悉它,可以使用它。

现在,这样做只会将代码的大小减少 1 行,虽然我确信通过巧妙地使用 ternary operators 或其他方法可以进一步减少代码质量,但作为一般规则,通过以下方式衡量代码质量行数是一个可怕的指标,永远不应该使用,尤其是当我们谈论像 Java 这样的编译语言时。我可以对下面的代码做很多事情,这会以牺牲可读性和/或性能为代价来减少行数,但是在程序员之间的竞争之外没有真正意义,比如code golf(但即使与您竞争最低的字符数,而不是行数)。

您应该争取最好的Big-O notation complexity,而不是追求更短的代码,这样您的代码就具有更高的性能,而更少的代码行不一定与性能相关。

public class CoolDude {
    public static void main(String[] args) {
        for (int i = 100; i <= 500; ++i) {
            if (i % 5 == 0) {
                if (i % 11 == 0) {
                    System.out.printf("Cool Dude - %d\n", i);
                } else {
                    System.out.printf("Cool - %d\n", i);
                }
            } else if (i % 11 == 0) {
                System.out.printf("Dude - %d\n", i);
            }
        }
    }
}

【讨论】:

  • 如果目标是最快的,更好的解决方案不会在 i 上迭代,而是在 5 的倍数和 11 的倍数上迭代,并始终检查最低的一个并相应地打印,就像我的第二个一样解决方案。
  • 你是对的。不过,对于初学者来说,这是一个简单而快速的重构。通常在这样的任务中,当它不是您正在检查的任何内容的倍数时,他们会让您打印出i 作为默认状态。当我第一次开始回答时,我的头脑仍然停留在那个范式中。如果是这种情况,您将无法迭代倍数。不过,我想知道,找到倍数然后对照最大值检查它们需要多少性能。在您进入实际逻辑之前,这会为每个循环添加至少 2 个和最多 3 个额外的操作。
【解决方案3】:
        IntStream.rangeClosed(100,500).forEach(i->{
        if(i%5 == 0 && i%11 == 0) {
            System.out.println("Cool Dude - "+i );
        } else if (i%5 == 0) {
            System.out.println("Cool - "+i );
        } else if (i%11 == 0) {
            System.out.println("Dude - "+i );
        }
    });

【讨论】:

  • 在这里使用stream 有什么改善呢?
  • IntStream 确实比传统的for loop 提供了一点优势。尤其是当您的号码范围超过 3 位数时,如果号码范围在 2 位数以内,我就不会费心去重构它。这基于我的生产级代码问题解决经验。 :) 干杯
  • 以什么方式边缘?速度?可读性?请详细说明。
【解决方案4】:

下面的代码应该会减少代码行数,尽管它看起来并没有运行得更快。它还纠正了连字符周围的间距,并可能简化了逻辑。

public class CoolDude {
public static void main(String args[]) {
    for (int i = 100; i <= 500; ++i) {
        StringBuilder coolDude = new StringBuilder(15); //15 chars max "Cool Dude - 495"
        if (i % 5 == 0) {
            coolDude.append("Cool ".toCharArray());
        }
        if (i % 11 == 0) {
            coolDude.append("Dude ".toCharArray());
        }
        if (coolDude.length() > 0) {
            System.out.println(coolDude.append(("- " + i).toCharArray()));
        }
    }
}
}

修订: 我的观点是,可以利用每次通过循环仅进行一次 mod 计算的优势。这在尝试使用 StringBuilders 和一行来节省时间时迷失了(正如其他人指出的那样,这不是一个有价值的目标)。我通过使用 print 和 println 来澄清。

public class CoolDude {
public static void main(String args[]) {
    boolean printed = false;
    for (int i = 100; i <= 500; ++i, printed = false) {
        if (i % 5 == 0) {
            System.out.print("Cool ");
            printed = true;
        }
        if (i % 11 == 0) {
            System.out.print("Dude ");
            printed = true;
        }
        if (printed) {
            System.out.println("- " + i);
        }
    }
}
}

【讨论】:

    猜你喜欢
    • 2015-07-12
    • 2011-04-09
    • 2021-12-15
    • 2022-10-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多