为了改进我的编程,我在Java中尝试这个问题。我到处寻找一个优雅的解决方案,无法找到它。
编写一个带有单个参数的程序,计算阶乘并打印出 屏幕上的值。此外,程序必须是交互式的,而不是终止后的 每次计算,并使用先前值表来提高性能。
如何使它在方法调用中检查它是否已经计算了值的阶乘?此代码的任何其他改进,以使其更具可读性或效率,也是值得赞赏的。
这是我到目前为止所写的内容。
public static void main(String[] args) {
int input = 0;
Scanner reader = new Scanner(System.in);
HashMap cache = new HashMap();
while(1 == 1){
do{
try {
System.out.println("Enter the number you would like to factor");
input = reader.nextInt();
} catch (InputMismatchException e){
reader.next();
}
} while(input <= 0);
if(cache.get(input) != null){
System.out.println("Found in cache");
System.out.println(input + "! = " + cache.get(input));
}
else {
cache.put(input, factorialRecursively(input));
System.out.println(input + "! = " + factorialRecursively(input));
}
}
}
public static int factorialIteratively(int a) throws InputMismatchException {
int temp = 1;
while(a > 0){
temp = temp * a;
a--;
}
return temp;
}
public static int factorialRecursively(int a) throws InputMismatchException{
if (a == 1){
return 1;
}
else {
return a * factorialRecursively(a-1);
}
}
答案 0 :(得分:2)
public static void main(String[] args) {
int input = 0;
try (Scanner reader = new Scanner(System.in)) {
Map<Integer, Integer> cache = new HashMap<Integer, Integer>();
cache.put(1, 1);
while (true) {
do {
try {
System.out.println("Enter the number you would like to factor");
input = reader.nextInt();
} catch (InputMismatchException e){
reader.next();
input = 0;
}
} while(input <= 0);
if(cache.get(input) != null) {
System.out.println("Found in cache");
System.out.println(input + "! = " + cache.get(input));
}
else {
int result = factorialRecursively(input, cache);
System.out.println(input + "! = " + result);
}
}
}
}
public static int factorialRecursively(int limit, Map<Integer, Integer> cache) {
int cacheSize = cache.size();
if (cacheSize < limit) {
int nextFactorial = cacheSize + 1;
System.out.println("Calculating and caching " + nextFactorial + "!");
cache.put(nextFactorial, cache.get(cacheSize) * nextFactorial);
return factorialRecursively(limit, cache);
}
else {
return cache.get(limit);
}
}
1)直接回答你的问题:“如何确定计算阶乘的方法,检查它是否已计算出一个值的阶乘”。所以我坚持使用递归方法,尽管你也可以使用相同的概念实现迭代版本
基本上,我们的想法是将结果缓存的引用传递给方法本身(Map<Integer, Integer> cache
参数),因此它负责在每个乘法步骤中存储得到的计算因子,而不仅仅是一个全因子具有已被计算。为此,我让方法从下到上计算阶乘,而不是相反。我们将最小的factorial存储在缓存中作为起点(cache.put(1, 1);
)。我添加了一条输出消息,显示计算和缓存阶乘的时间,并通过测试代码,您可以看到一个特定的阶乘仅被计算并存储一次。
2)使用Map<Integer, Integer> cache = new HashMap<Integer, Integer>();
代替HashMap cache = new HashMap();
a)从Java 1.5开始,集合已经变成通用的(长篇故事,在此范围之外),并且在引用时应该参数化。所以我们在这里说,我想存储整数值(计算因子),我可以使用整数键(因子源)访问。
b)代码编译并允许我们使用整数原语而不是Integer类对象的原因是因为一种名为auto-boxing的机制将整数原语无缝地包装到Integer对象中,反之亦然。同样,超出范围,但应该注意它
c)我们之后的功能是Map
接口的功能,HashMap
恰好是其实现。除非引用代码依赖于HashMap
特定方法(不太可能),否则最好将变量声明为相应的集合接口(如List
等ArrayList
),而不是实施班。
3)InputMismatchException仅由Scanner类抛出,因此不需要被任何不调用Scanner
nextInt()
方法的代码抛出。
4)使用true
代替1 == 1
。在实践中等效,但使用布尔值更具可读性。
5)只调用factorialRecursively
方法一次。您的代码调用该方法两次,这是不必要的。如果你追求效率和优雅,你应该只调用一次方法并将结果存储在一个变量中。
6)使用try (Scanner reader = new Scanner(System.in)) { ...
代替Scanner reader = new Scanner(System.in);
。 Scanner
对象必须始终调用其close()
方法来清理资源。在较旧的Java版本中,这是使用try {} finally {}语句实现的,但是如果类实现了AutoCloseable接口,则更高版本允许使用此语法(try-with-resources语句)。这意味着始终可以保证调用close()方法。
7)最后但并非最不重要:int
和Integer
的使用,我没有改变。正如@indivisible的评论中所建议的那样,您应该了解data type limitations。 int
只能保存由31位+符号(-2 ^ 31 -1到2 ^ 31)表示的数字,这会将此代码限制为16 !,之后结果将变为错误。如果您希望生成更大的数字,请使用long
/ Long
。无论如何,真的再次超出了这个问题的范围。
玩得开心:)