Java 一个单链表怎么可能有两个头,找到它们的“头”意味着什么;公共节点“;?
以下方法的JavaDocs包括: 问题中的单链表有两个头,Java 一个单链表怎么可能有两个头,找到它们的“头”意味着什么;公共节点“;?,java,singly-linked-list,Java,Singly Linked List,以下方法的JavaDocs包括: 问题中的单链表有两个头,n1和n2,它们合并在一个公共节点上。返回可从n1和n2访问的第一个公共节点。这必须在O(n)时间内运行 我不明白这个代码的目的。一个单链表怎么可能有两个头?什么是公共列表(或公共节点),为什么返回 是否有人可以提供一些输入列表的示例,以及findCommonList方法返回后的列表或列表的外观 代码是: public static<E> ListNode<E> findCommonList(ListNode<
n1
和n2
,它们合并在一个公共节点上。返回可从n1
和n2
访问的第一个公共节点。这必须在O(n)时间内运行
我不明白这个代码的目的。一个单链表怎么可能有两个头?什么是公共列表(或公共节点),为什么返回
是否有人可以提供一些输入列表的示例,以及findCommonList
方法返回后的列表或列表的外观
代码是:
public static<E> ListNode<E> findCommonList(ListNode<E> n1, ListNode<E> n2) {
int length1 = getLength(n1);
int length2 = getLength(n2);
if (length1 > length2)
n1 = advance(n1, length1 - length2);
else
n2 = advance(n2, length2 - length1);
while (n1 != n2) {
n1 = n1.next;
n2 = n2.next;
}
return n1; }
private static<E> ListNode<E> advance(ListNode<E> n, int k) {
while (k > 0) {
n = n.next;
k--; }
return n;
}
private static<E> int getLength(ListNode<E> n) {
int total = 0;
while (n != null) {
total++;
n = n.next; }
return total;
}
公共静态ListNode findCommonList(ListNode n1,ListNode n2){
int length1=getLength(n1);
int length2=getLength(n2);
如果(长度1>长度2)
n1=前进(n1,长度1-长度2);
其他的
n2=前进(n2,长度2-长度1);
而(n1!=n2){
n1=n1.next;
n2=n2.next;
}
返回n1;}
专用静态ListNode高级(ListNode n,int k){
而(k>0){
n=n.next;
k--;}
返回n;
}
私有静态int getLength(ListNode n){
int-total=0;
while(n!=null){
总计++;
n=n.next;}
返回总数;
}
我看不到ListNode
的代码,但我猜这是一个非常典型的单链接列表,引用了E
类型的一些数据,并引用了下一个ListNode
,称为next
。最后一个ListNode
将其next
指向null
。忽略对数据的引用,典型列表如下所示:
lnA→lnB→lnC→…→lnZ→null
这种结构的一个(许多)问题是没有一个列表“拥有”这些ListNode
实例中的任何一个,因此多个列表可能会纠结在一起:
ln0→ln1→ln2↘
lnQ→lnR→…→lnZ→null
lnA→lnB→lnC↗
findCommonList
方法接受两个ListNode
引用,n1
和n2
,然后搜索它们有共同点的第一个“右侧”节点,这标志着它们共同尾部的开始
n1和n2作为一条共同的尾巴共享什么实际上取决于它们从哪里开始。把它们放在明显的地方:
n1
↓
ln0→ln1→ln2↘
lnQ→lnR→…→lnZ→null
lnA→lnB→lnC↗
↑
n2
…将返回lnQ
作为其公共尾部的开始。(如果n2
是从lnZ
开始的,那么显然结果不可能包括lnQ
——它不再在其中一个列表中,因此对这两个列表都不常见。)
JavaDoc意味着此代码仅在上述情况下有效,但它也处理一些可能在开始时看起来非常不同的相关情况,例如当n1
和n2
指向同一列表的不同元素时:
甚至当他们指向两个不相关的列表时。。。
由于所有列表都以引用null
结束,因此两个“完全独立”的列表将返回null
作为其(零长度)公共尾部的开始:
n1
↓
ln0→ln1→ln2→ln3→ln4↘
null
lnA→lnB→lnC↗
↑
n2
如何findCommonList
工作
findCommonList
要做的第一件事是找出n1
和n2
距离各自列表的末尾有多远(每个null
之间分隔了多少个元素)
在本例中,n1
比n2
远“2”:
n1
↓
ln0→ln1→ln2→ln3→ln4↘
lnQ→…→lnZ→null
lnA→lnB→lnC↗
↑
n2
然后,它向前推进两个参考中的较远的一个,以便它与另一个参考之间的距离与null
相同。它跳过的元素不可能是公共尾部的一部分,因为公共尾部不可能长于一个输入列表
前进n1
后:
n1
↓
ln0→ln1→ln2→ln3→ln4↘
lnQ→…→lnZ→null
lnA→lnB→lnC↗
↑
n2
现在我们已经到达while
循环,它可以被改写为:
START:
if n1 and n2 point to the same ListNode:
return that ListNode
otherwise:
advance n1 and n2 each one hop to the right
go back to "START"
这就是我上面所说的“搜索他们共同拥有的‘右侧’第一个节点”。完成后,n1
和n2
都将指向相同的ListNode
,lnQ
,并返回:
n1
↓
ln0→ln1→ln2→ln3→ln4↘
lnQ→…→lnZ→null
lnA→lnB→lnC↗
↑
n2
请注意,这在我上面概述的其他情况下也适用
如果n1
和n2
指两个完全独立的列表:
n1
↓
ln0→ln1→ln2→ln3→ln4↘
null
lnA→lnB→lnC↗
↑
n2
首先,进一步的参考将推进:
n1
↓
ln0→ln1→ln2→ln3→ln4↘
null
lnA→lnB→lnC↗
↑
n2
然后,while
循环将使两个引用同步前进,直到它们到达两个列表共同的唯一“节点”null
:
n1
↓
ln0→ln1→ln2→ln3→ln4↘
null
lnA→lnB→lnC↗
↑
n2
如果n1
和n2
已经指向相同的列表,则更容易:
n1
↓
ln0→ln1→ln2→ln3→ln4→…→null
↑
n2
findCommonList
将从推进远引用开始,与前面相同:
n1
↓
ln0→ln1→ln2→ln3→ln4→…→null
↑
n2
…而且已经完成了findCommonList
将立即返回对ln3
的引用,而不会在循环期间执行主体
最后,如果n1
和n2
开始指向相同的ListNode
:
n1
↓
ln0→ln1→ln2→ln3→ln4→…→null
↑
n2
…调整步骤什么也不做(“前进0跳”),然后返回ln0
,再次没有执行循环的主体。也许我没有清楚地表达我的想法,我重新编辑了我的问题。我提交了一个编辑,以使Weiting的问题更清楚,因为最初的标题只是重述了代码的作用,这意味着一个非常不同的——而且非常广泛的——问题。我认为真正的问题值得重新讨论(尽管我没有机会打那个电话)。它在问为什么需要这个代码:一个单链表怎么可能有两个头?要想知道只有一个传出指针的节点如何仍然会纠结在一起,需要一些想象力。(魏婷:代码本身还可以改进——你能修复缩进吗?)太好了,非常感谢!
n1
↓
ln0→ln1→ln2→ln3→ln4→…→null
↑
n2