Java 计算2个链表中的值之和
所以我最近在一次采访中遇到了一个编程问题 有两个链表,每个节点的存储从1到9的值(表示数字的一个索引)。因此123将是一个链表1->2->3 任务是创建一个函数:Java 计算2个链表中的值之和,java,algorithm,linked-list,Java,Algorithm,Linked List,所以我最近在一次采访中遇到了一个编程问题 有两个链表,每个节点的存储从1到9的值(表示数字的一个索引)。因此123将是一个链表1->2->3 任务是创建一个函数: 静态LinkedListNode getSum(LinkedListNode a,LinkedListNode b) 这将返回两个链表参数中的值之和 如果数组a为:1->2->3->4 而数组b是:5->6->7->8 答案应该是:6->9->1->2 这是我的算法: 遍历a和b中的每个节点,将这些值作为一个整数进行相加。用这些值创建
静态LinkedListNode getSum(LinkedListNode a,LinkedListNode b)
这将返回两个链表参数中的值之和
如果数组a为:1->2->3->4
而数组b是:5->6->7->8
答案应该是:6->9->1->2
这是我的算法:
遍历a和b中的每个节点,将这些值作为一个整数进行相加。用这些值创建一个新的链表
代码如下:我假设它的运行复杂度大致为O(3n)。一次通过每个数组输入,一次创建输出数组
有什么改进吗?更好的算法。。。或代码改进
public class LinkedListNode {
LinkedListNode next;
int value;
public LinkedListNode(int value) {
this.value = value;
this.next = null;
}
static int getValue(LinkedListNode node) {
int value = node.value;
while (node.next != null) {
node = node.next;
value = value * 10 + node.value;
}
return value;
}
static LinkedListNode getSum(LinkedListNode a, LinkedListNode b) {
LinkedListNode answer = new LinkedListNode(0);
LinkedListNode ans = answer;
int aval = getValue(a);
int bval = getValue(b);
int result = aval + bval;
while (result > 0) {
int len = (int) Math.pow((double) 10,
(double) String.valueOf(result).length() - 1);
int val = result / len;
ans.next = new LinkedListNode(val);
ans = ans.next;
result = result - val*len;
}
return answer.next;
}
}
可以通过从后向前构建生成的链表来优化:
int aval = getValue(a);
int bval = getValue(b);
int result = aval + bval;
LinkedListNode answer = null;
while (result > 0) {
int val = result % 10;
LinkedListNode prev = answer;
answer = new LinkedListNode(val);
answer.next = prev;
result /= 10;
}
if (answer == null) {
// Assuming you want to return 0 rather than null if the sum is 0
answer = new LinkedListNode(0);
}
return answer;
这样可以避免重复调用Math.pow
我认为你使用的整体算法应该是最快的。想到的另一种方法是对每对数字执行某种带进位的加法运算(即“手动”进行加法),但这很可能会慢一些。通常在这些类型的练习中,人们希望在不首先转换为更常见的中间形式(如整数)的情况下执行运算。我希望得到的下一个问题是,“如果数字是100位长怎么办?”尝试仅使用链表来解决它,尽管您可能必须反转操作数的方向以提供合理的运行时间。让我试一试
static LinkedListNode getSum(LinkedListNode a, LinkedListNode b) {
//some checks first if any computation will be needed at all
if(a == null) {
if(b == null)
return null;
else
return b;
} else if (b == null)
return a;
//initialize the variables
LinkedListNode stacka = null;
LinkedListNode stackb = null;
LinkedListNode ans = null;
LinkedListNode temp = null;
//move the contents of a & b into stacka & stackb respectively at the same time
//best case is when a & b are of equal size
//worst case is when the size of a & b are worlds apart.
while(a != null || b != null){
if(a != null) {
if(stacka == null){
stacka = new LinkedListNode(a.value);
} else {
temp = new LinkedListNode(a.value);
temp.next = stacka;
stacka = temp;
}
}
if(b != null) {
if(stackb == null){
stackb = new LinkedListNode(b.value);
} else {
temp = new LinkedListNode(b.value);
temp.next = stackb;
stackb = temp;
}
}
if(a != null) a = a.next;
if(b != null) b = b.next;
}
int remainder = 0;
//just pop off the stack then merge! also, don't forget the remainder~
while(stacka != null || stackb != null){
//pop from the top of the stack
int i = ((stacka == null) ? 0 : stacka.value) + ((stackb == null) ? 0 : stackb.value) + remainder;
//set the value of the remainder if any as well as the value of i
remainder = i / 10;
i %= 10;
temp = new LinkedListNode(i);
if(ans == null) {
ans = temp;
} else {
temp.next = ans;
ans = temp;
}
if(stacka != null) stacka = stacka.next;
if(stackb != null) stackb = stackb.next;
}
return ans;
}
因为我没有使用getValue()函数,所以在最好的情况下应该是O(2n)左右。
我在这里做的是使用LinkedListNode作为堆栈临时存储节点,同时反转它们,然后一次弹出一个值以填充输出LinkedListNode
最后,这两种算法仍然处于O(n)之下,因此差异可以忽略不计
如果我有时间的话,我将尝试稍后制作一个递归版本
另外,如果我没有在我的if-else语句中添加大括号,那么很难使用答案表单对它们进行制表。首先,浏览两个列表,翻转箭头的方向,并以内存中的最终节点结束。这是线性时间和恒定空间
现在您有了一对链表,它们表示从最低数字到最高数字的数字。再次浏览列表,创建新的链接列表,并在运行时将箭头向后翻转。这是线性时间和线性空间(对于新列表)。最初的问题是Java,但这里有一个非常简单的Scala解决方案。它在列表中留下了0,因此它们的长度相同。然后,它将列表拉到一起,这样我们就有了一个单一的对列表。最后,它将沿着进位值从右向左添加对。(与您在一年级时学习如何添加数字的方式相同。)它展示了我们如何使用函数技术快速地用少量代码解决问题:
def add(nums1: List[Int], nums2: List[Int]): List[Int] = {
val nums1Size = nums1.size
val nums2Size = nums2.size
val maxSize = nums1Size max nums2Size
val nums1Padded = List.fill(maxSize - nums1Size)(0) ++ nums1
val nums2Padded = List.fill(maxSize - nums2Size)(0) ++ nums2
val zipped = nums1Padded.zip(nums2Padded)
val (result, carry) = zipped.foldRight((List.empty[Int], 0)) { (curr, r) =>
val sum = curr._1 + curr._2 + r._2
((sum % 10) :: r._1, sum / 10)
}
if (carry > 0) carry :: result else result
}
看起来任务是在十进制数字表示为链表的位置添加数字。你应该把它添加到问题中,因为这很难理解。只是让大家知道,这个问题已经有了一个副本。这个副本最初在程序员处交叉发布,并迁移到这里而不是关闭。手动进行进位可能会更快,因为你只添加了个位数和9+9=18,这意味着您只需测试它是否大于10,如果是,则减去10并进行进位。但是,由于我们使用的是一个存储单个数字的链表,我认为它不会在速度上产生真正的差异,因为它几乎肯定会被所有的指针解引用所淹没。从性能角度来看,主要问题是,您需要遍历每个列表两次,一次才能到达最低有效数字,当我们把每一对数字相加时,如果我们改变问题,让链表从最小的数字存储到最大的数字,这个问题就会消失。这种表示法实际上在一般情况下也更有意义,至少对于单链接列表是如此。