我正在准备面试。我得到的问题是:两个数字由一个链表表示,其中每个节点都包含一个数字。这些数字以相反的顺序存储,因此1的数字位于列表的开头。编写一个函数,将两个数字相加,并以链表的形式返回总和。建议的答案将每个数字单独相加,并保留一个"进位"数字。例如,如果两个数字的第一位是"5"one_answers"7"。该算法将"2"记录在结果和的第一位,并将"1"作为"进位"添加到结果的第10位。然而,我的解决方案是遍历两个链表,并将它们转换为两个整数。然后我把数字加起来,把和转换成一个新的链表。我的解决方案不是更直接、更高效吗?谢谢
虽然您的解决方案可能更简单,但我不认为它实际上更高效。
我假设"正确"的算法是这样的:
- 弹出两个列表的第一个元素
- 将它们加在一起(如果有进位,则加进位),并使用一位数字创建一个新节点
- 传递进位(将和除以10得到实际要进位的东西),然后重复1)和2),每个连续的节点都被前一个节点指向
当我将您的算法与该算法进行比较时,我看到的主要内容是:
- 在内存方面,您希望在最终链表本身的顶部创建两个
BigInteger
来存储中间值(我假设您使用BigInteger
或一些等效的Object
来避免int
或long
的约束)。原始算法不使用超过两个int
来进行中间计算,因此从长远来看,原始算法实际上使用较少的内存 - 您还建议您使用
BigInteger
s而不是使用int
s来完成所有运算。虽然BigInteger
可能确实优化到了比原始运算慢不了多少的程度,但我非常怀疑调用BigInteger#add
是否比在int
s上执行+
运算快
此外,还有一些值得思考的东西。假设您没有像BigInteger
这样方便的东西来存储任意大的整数。然后你必须有一些方法来存储任意大的整数,这样你的算法才能正常工作。在那之后,你基本上需要一种添加任意大整数的方法来添加任意大的整数,你最终会遇到一个问题,要么你必须做一些类似于原始算法的事情,要么你最终在子例程中使用完全不同的表示(yikes)。
(假设用"integer"表示int
。)
您的解决方案不会扩展到int
中可以容纳的数字之外,而原始解决方案仅受可用内存量的限制。
就效率而言,您的解决方案没有什么比原来的解决方案更高效的了。
当然,您的解决方案更易于描述,而且在某些情况下可能会提出一个论点,即在与大型团队合作时,您的方案将产生的代码的可读性会更好。
然而,大多数时候,他们建议的答案是更高效的内存,可能更高效的CPU。
您建议浏览第一个链接列表,将其存储为数字(+1存储)。通过第二个,将其存储为数字(+1存储)。将2个数字相加,保存结果(+1存储)。将此号码转换为链接列表并保存(+1存储)
他们的解决方案包括遍历第一个和第二个链表,同时写入第三个,并将其存储为新的(+1存储)
这是一个+1商店,而不是你的+4商店。这看起来可能不多,但如果我们尝试同时添加n对数字(在分布式系统或其他系统上),则会看到4n个存储,而不仅仅是n个存储。这可能是一件大事。