1输入两个链表,找出它们的第一个公共节点
1.1使用集合,运用Hash特性进行检测
public ListNode findFirstCommonNodeBySet(ListNode headA, ListNode headB) {
Set<ListNode> set = new HashSet<>();
while (headA != null) {
set.add(headA);
headA = headA.next;
}
while (headB != null) {
if (set.contains(headB))
return headB;
headB = headB.next;
}
return null;
}
运用contains()方法,遍历链表A之后和链表B进行对比
1.2使用栈
import java.util.Stack;
public ListNode findFirstCommonNodeByStack(ListNode headA, ListNode headB) {
Stack<ListNode> stackA=new Stack();
Stack<ListNode> stackB=new Stack();
while(headA!=null){
stackA.push(headA);
headA=headA.next;
}
while(headB!=null){
stackB.push(headB);
headB=headB.next;
}
ListNode preNode=null;
while(stackB.size()>0 && stackA.size()>0){
if(stackA.peek()==stackB.peek()){
preNode=stackA.pop();
stackB.pop();
}else{
break;
}
}
return preNode;
}
基于栈先进后出的特性,将两个链表分别入栈,然后进行出栈,最后一组相同的正是两个链表的公共节点
1.3拼接两个字符串
public ListNode findFirstCommonNode(ListNode pHead1, ListNode pHead2) {
if(pHead1==null || pHead2==null){
return null;
}
ListNode p1=pHead1;
ListNode p2=pHead2;
while(p1!=p2){
p1=p1.next;
p2=p2.next;
if(p1!=p2){
//一个链表访问完了就跳到另外一个链表继续访问
if(p1==null){
p1=pHead2;
}
if(p2==null){
p2=pHead1;
}
}
}
return p1;
}
试想一下,当两条线相交成一条线的时候,那么可以说明,这两条线在交点右侧的部分是完全相同的。这句话看起来是废话,但是运用在编程当中,可以将两个链表相互收尾相连,形成两条等长的链表,这样可以对两条链表进行同时遍历。当有相同的节点时,就是原本两条链表的交点。
在上面这段代码中,因为想要节省空间,于是增加了判断,使用指针指向链表,当链表p1遍历完了,指针立马指向链表p2,如同两个链表连在一起一样。但是这就会遇到一种情况,当两个链表没有交点时且他们的指针同时指向null的时候,这个时候本来应该已经比较结束了,但是指针又会重新连接一遍链表,造成死循环。因此对代码进行优化加入p1!= p2的判断
1.4差和双指针
public ListNode findFirstCommonNode(ListNode pHead1, ListNode pHead2) {
if(pHead1==null || pHead2==null){
return null;
}
ListNode current1=pHead1;
ListNode current2=pHead2;
int l1=0,l2=0;
//分别统计两个链表的长度
while(current1!=null){
current1=current1.next;
l1++;
}
while(current2!=null){
current2=current2.next;
l2++;
}
current1=pHead1;
current2=pHead2;
int sub=l1>l2?l1-l2:l2-l1;
//长的先走sub步
if(l1>l2){
int a=0;
while(a<sub){
current1=current1.next;
a++;
}
}
if(l1<l2){
int a=0;
while(a<sub){
current2=current2.next;
a++;
}
}
//同时遍历两个链表
while(current2!=current1){
current2=current2.next;
current1=current1.next;
}
return current1;
}
可以知道的是,当两条链表可以通过某个节点后汇聚成一条链表,并且两条链表的长度并不一样长的时候,这两条链表的相交点一定不在短链表比长链表短的那一部分上,因此可以先去掉长链表开始时多的那一部分,从两个链表长度相等时开始比较