一位朋友正在在线进行Scala课程并分享了此课程。
# Write a recursive function that counts how many different ways you can make
# change for an amount, given a list of coin denominations. For example, there
# are 3 ways to give change for 4 if you have coins with denomiation 1 and 2:
# 1+1+1+1, 1+1+2, 2+2.
如果您正在参加并且仍在研究解决方案,请不要阅读此内容!
(免责声明:即使我的Python解决方案可能是错误的,我也不想影响您的思维方式(如果您正在学习一种或另一种方式的学习方式!) “解决” ...)
那边...
我以为我可以在Python中使用它,因为我没有Scala的排行榜(我自己不在这门课程上,只是对学习Python和Java感兴趣,欢迎“练习”进行练习)。
这是我的解决方案,我想使用尽可能紧凑的表示法移植到Java:
def show_change(money, coins, total, combo):
if total == money:
print combo, '=', money
return 1
if total > money or len(coins) == 0:
return 0
c = coins[0]
return (show_change(money, coins, total + c, combo + [c]) +
show_change(money, coins[1:], total, combo))
def make_change(money, coins):
if money == 0 or len(coins) == 0:
return 0
return show_change(money, list(set(coins)), 0, [])
def main():
print make_change(4, [2, 1])
if __name__ == '__main__':
main()
题
我可以在Java中做得这么紧凑,如果有帮助,允许使用JDK外部的库吗?
我尝试自己进行移植,但是它变得非常冗长,我认为通常的“一定有更好的方法”!
这是我的尝试:
import java.util.ArrayList;
import java.util.List;
import com.google.common.collect.Lists;
import com.google.common.primitives.Ints;
public class MakeChange {
static int makeChange(int money, int[] coins) {
if (money == 0 || coins.length == 0) {
return 0;
}
return showChange(money, Ints.asList(coins), 0, new ArrayList<Integer>());
}
static int showChange(int money, List<Integer> coins, int total,
List<Integer> combo) {
if (total == money) {
System.out.printf("%s = %d%n", combo, total);
return 1;
}
if (total > money || coins.isEmpty()) {
return 0;
}
int c = coins.get(0);
List<Integer> comboWithC = Lists.newArrayList(combo);
comboWithC.add(c);
return (showChange(money, coins, total + c, comboWithC) + showChange(money,
coins.subList(1, coins.size()), total, combo));
}
public static void main(String[] args) {
System.out.println(makeChange(4, new int[] { 1, 2 }));
}
}
具体来说,我不喜欢的是要做下面的事情,只是传递列表的副本并附加一个元素:
List<Integer> comboWithC = Lists.newArrayList(combo);
comboWithC.add(c);
请告诉我Java的紧凑性和可读性。我还是这两种语言的初学者。
参考方案
确实,您在这里所做的几乎所有操作都可以直接转换为Java,而无需太多冗长的内容。
例如:
def make_change(money, coins):
if money == 0 or len(coins) == 0: return 0
return calculate_change(money, list(set(coins)), 0)
Java的明显等效项是:
public static int make_change(int money, int coins[]) {
if (money == 0 || coins.length == 0) return 0;
return calculate_change(money, coins, 0);
}
在这里和那里多了几句话,由于右括号而增加了一行,当然还有显式类型……但是除此之外,没有什么大的变化。
当然,更多的Python和Javariffic版本(等效词是什么?)将是:
def make_change(money, coins):
if money == 0 or len(coins) == 0:
return 0
return calculate_change(money, list(set(coins)), 0)
Java的明显等效项是:
public static int make_change(int money, int coins[]) {
if (money == 0 || coins.length == 0) {
return 0;
}
return calculate_change(money, coins, 0);
}
因此,Java获得了一个额外的结尾括号加上一些空格。仍然没什么大不了的。
将整个内容放到一个类中,然后将main
转换为方法,大约需要增加3行。初始化一个显式数组变量而不是使用[2, 1]
作为原义还要多1个。 System.out.println
比print
长几个字符,length
比len
长3个字符,并且每个注释使用两个字符//
而不是一个#
。但我怀疑这是您所担心的。
最终,总共只有一条线很棘手:
return (calculate_change(money, coins, total + c, combo + [c]) +
calculate_change(money, coins[1:], total, combo))
Java int coins[]
没有任何办法说“给我一个新数组,其中包含当前数组的尾部”。最简单的解决方案是传递一个额外的start
参数,因此:
public static int calculate_change(int money, int coins[], int start, int total) {
if (total == money) {
return 1;
}
if (total > money || coins.length == start) {
return 0;
}
return calculate_change(money, coins, 0, total + coins[start]) +
calculate_change(money, coins, start + 1 total);
}
实际上,几乎所有内容都可以轻易地转换为C。您只需要传递另一个数组长度的参数,因为您无法像Java或Python那样在运行时计算它。
您抱怨的那一行是一个有趣的观点,值得多加思考。在Python中,您已经(实际上):
comboWithC = combo + [c]
使用Java的列表,这是:
List<Integer> comboWithC = Lists.newArrayList(combo);
comboWithC.add(c);
这比较冗长。但这是故意的。 Java List<>
不能以这种方式使用。对于小型列表,复制所有内容都没什么大不了的,但是对于大型列表,这可能会造成巨大的性能损失。 Python的list
是在这样的假设下设计的:在大多数情况下,您正在处理小列表,并且将它们复制到周围非常好,因此编写起来应该很简单。 Java的List
是基于这样的假设而设计的,即有时您要处理庞大的列表,并且将它们复制到周围是一个非常糟糕的主意,因此您的代码应清楚表明您确实想要这样做。
理想的解决方案是要么使用不需要复制列表的算法,要么找到旨在以这种方式复制的数据结构。例如,在Lisp或Haskell中,默认列表类型非常适合这种算法,并且应该可以在网上找到大约69105个“ Java中的Lisp样式列表”或“ Java缺点”的食谱。 (当然,您也可以在List周围编写一个琐碎的包装,添加了像Python的__add__
这样的“ addToCopy”方法,但这可能不是正确的答案;您想编写惯用的Java,或者为什么要使用Java而不是其中之一其他许多JVM语言?)
java字节代码(已编译的语言,也称为目标代码)与机器代码(当前计算机的本机代码)之间有什么区别?我读过一些书,他们将字节码称为二进制指令,但我不知道为什么。 参考方案 字节码是独立于平台的,在Windows中运行的编译器编译的字节码仍将在linux / unix / mac中运行。机器代码是特定于平台的,如果在Windows x86中编译,则它将仅在Win…
java:继承 - java有哪些替代继承的方法? java大神给出的解决方案 有效的Java:偏重于继承而不是继承。 (这实际上也来自“四人帮”)。他提出的理由是,如果扩展类未明确设计为继承,则继承会引起很多不正常的副作用。例如,对super.someMethod()的任何调用都可以引导您通过未知代码的意外路径。取而代之的是,持有对本来应该扩展的类的引用,然后委托给它。这是与Eric…
Java:BigInteger,如何通过OutputStream编写它 - java我想将BigInteger写入文件。做这个的最好方式是什么。当然,我想从输入流中读取(使用程序,而不是人工)。我必须使用ObjectOutputStream还是有更好的方法?目的是使用尽可能少的字节。谢谢马丁 参考方案 Java序列化(ObjectOutputStream / ObjectInputStream)是将对象序列化为八位字节序列的一种通用方法。但…
Java-如何将此字符串转换为日期? - java我从服务器收到此消息,我不明白T和Z的含义,2012-08-24T09:59:59Z将此字符串转换为Date对象的正确SimpleDateFormat模式是什么? java大神给出的解决方案 这是ISO 8601标准。您可以使用SimpleDateFormat simpleFormat = new SimpleDateFormat("yyyy-MM…
Java:从类中查找项目名称 - java仅通过类的实例,如何使用Java反射或类似方法查找项目名称?如果不是,项目名称(我真正想要的是)可以找到程序包名称吗? 参考方案 项目只是IDE使用的简单组织工具,因此项目名称不是类或JVM中包含的信息。要获取软件包,请使用Class#getPackage()。然后,可以调用Package#getName()将包作为您在代码的包声明中看到的String来获取…