Java 合并两个排序的单链表
在寻找一些考试练习时,我在Leetcode上遇到了这个问题,我提出了以下解决方案:Java 合并两个排序的单链表,java,algorithm,merge,linked-list,Java,Algorithm,Merge,Linked List,在寻找一些考试练习时,我在Leetcode上遇到了这个问题,我提出了以下解决方案: public class ListNode { int val; ListNode next; ListNode(int x) { val = x; } } public class Solution { public ListNode mergeTwoLists(ListNode l1, ListNode l2) { // base case: if any o
public class ListNode {
int val;
ListNode next;
ListNode(int x) { val = x; }
}
public class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
// base case: if any one of the lists are empty then we are done.
if (l1 == null) return l2;
else if (l2 == null) return l1;
ListNode head = new ListNode(-1);
// dummy head node
ListNode prev = head; // pointer to do the modifications on the list
while ((l1 != null) && (l2 != null)) {
// while both lists arent empty
int val;
if (l1.val < l2.val) {
val = l1.val;
l1 = l1.next;
} else {
val = l2.val;
l2 = l2.next;
}
ListNode curr = new ListNode(val); // creates a new node with the chosen value
prev.next = curr; // update pointers
prev = curr;
}
// one of the list is finished. we add the rest onto the list ln
if (l1 == null) prev.next = l2;
else prev.next = l1;
return head.next;
}
}
公共类ListNode{
int-val;
listnodenext;
ListNode(intx){val=x;}
}
公共类解决方案{
公共ListNode合并列表(ListNode l1、ListNode l2){
//基本情况:如果任何一个列表为空,那么我们就完成了。
if(l1==null)返回l2;
else if(l2==null)返回l1;
ListNode头=新ListNode(-1);
//虚拟头节点
ListNode prev=head;//对列表进行修改的指针
而((l1!=null)和&(l2!=null)){
//虽然两个列表都不是空的
int-val;
if(l1.val
它似乎通过了所有测试——但我的问题是,它比提交的解决方案的90%慢。我最近学习了LinkedList,但我仍然对这个概念不太熟悉,这就是为什么在理解过程中可能会出现一些失误,导致这里的代码效率低下。如果有人能解释如何改进我的实现,我将不胜感激。您的代码有两个问题 首先,它与输入数据不一致。如果其中一个输入列表为空,则例程返回另一个输入列表作为结果。另一方面,如果两个输入列表均为非空,则例程将创建新项以构建结果列表。但是,当一个输入列表在合并过程中耗尽时,另一个列表的其余部分将附加到结果列表中。最终,结果列表部分由新节点和其中一个输入列表的尾部组成 这会导致创建重复节点和销毁原始节点(这些节点已被其副本替换)的不必要开销 为了避免这种情况,直接使用从输入列表中获取的节点构建结果列表。这样就不需要创建新节点,不需要回收旧节点,在复制前不需要保留中间变量
val
,如果扩展了ListNode
类,就不会忘记复制其他数据成员的风险
另一种是对输出节点进行排序。使用“小于”运算符决定是从l1
还是从l2
获取下一个节点。那是错误的。您应该使用“小于或等于”,因此对于相等键,您首先从l1
获取节点,然后从l2
获取节点。这样,具有相同键值val
,但在其他方面不同(例如,它们具有其他数据成员)的节点将保持原始顺序。我们称之为稳定排序
实施:
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
ListNode head = new ListNode(-1); // temporary head node
ListNode last = head; // the last item of the list; we append here
while ((l1 != null) && (l2 != null)) { // while both lists arent empty
if (l1.val <= l2.val) { // 'or equal' for stable merging
last.next = l1; // append the chosen node to result list
l1 = l1.next; // skip (effectively remove) it in input list
} else {
last.next = l2;
l2 = l2.next;
}
last = last.next; // the appended node becomes last
}
// one of the lists is finished - append the rest of the other one
if (l1 == null) last.next = l2;
else last.next = l1;
return head.next;
}
为什么只在方法末尾添加其余节点时创建新节点?似乎您不必创建新节点,只需(重新)使用已传递的节点就可以提高性能,特别是对于长列表。如何知道您的代码比解决某些未指定问题的其他未知代码慢?
null
list!=空列表。检查列表的size()
及其空值value@pvg恐怕这是我能说的最具体的了。原来的问题是这样的:你只是想说得更具体一些,也许不是。这并没有回答问题,这是对练习的回答。@pvg它没有回答吗?OP询问“是否有人可以解释如何改进我的实现”。这是一个例子,如何改进它们的实现:避免创建不必要的对象,并重新链接输入数据;完全按照任务描述:不是“使用合并数据创建新列表”,而是“合并输入列表”(他们说:'')。它没有解释任何事情,只是删除了一个实现,没有说明它如何优于poster的实现,为什么性能特征不同,等等。它只是一堆代码。这是一个糟糕的答案,就像“为什么这一团代码不起作用”是一个可标记的糟糕问题一样。@pvg也许CiaPan可以通过添加更多的澄清来改进答案,但就我个人而言,我发现这个答案在消化代码后很有帮助-这,我想我的目标是找到并理解更好的实现背后的原因。@user2938375这很好,但网站的目的是收集许多人认为有用的问题和答案,而不是充分回答你个人的特定问题。这就是为什么它有关于什么是好的问题和答案的指导方针。
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
if (l1 == null) return l2;
else if (l2 == null) return l1; // make sure both lists aren't empty
ListNode head = null; // the resulting list's head
if (l1.val <= l2.val) { // choose the head node
head = l1;
l1 = l1.next;
} else {
head = l2;
l2 = l2.next;
}
ListNode last = head; // the last item of the list; we append here
while ((l1 != null) && (l2 != null)) { // while both lists arent empty
if (l1.val <= l2.val) { // 'or equal' for stable merging
last.next = l1; // append the chosen node to result list
l1 = l1.next; // skip (effectively remove) it in input list
} else {
last.next = l2;
l2 = l2.next;
}
last = last.next; // the appended node becomes last
}
// one of the lists is finished - append the rest of the other one
if (l1 == null) last.next = l2;
else last.next = l1;
return head;
}