问题描述
剑指 Offer 52. 两个链表的第一个公共节点
输入两个链表,找出它们的第一个公共节点。
如下面的两个链表:
在节点 c1 开始相交。
示例 1:
输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
输出:Reference of the node with value = 8
输入解释:相交节点的值为 8 (注意,如果两个列表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。
示例 2:
输入:intersectVal = 2, listA = [0,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1
输出:Reference of the node with value = 2
输入解释:相交节点的值为 2 (注意,如果两个列表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [0,9,1,2,4],链表 B 为 [3,2,4]。在 A 中,相交节点前有 3 个节点;在 B 中,相交节点前有 1 个节点。
示例 3:
输入:intersectVal = 0, listA = [2,6,4], listB = [1,5], skipA = 3, skipB = 2
输出:null
输入解释:从各自的表头开始算起,链表 A 为 [2,6,4],链表 B 为 [1,5]。由于这两个链表不相交,所以 intersectVal 必须为 0,而 skipA 和 skipB 可以是任意值。
解释:这两个链表不相交,因此返回 null。
注意:
如果两个链表没有交点,返回 null.
在返回结果后,两个链表仍须保持原有的结构。
可假定整个链表结构中没有循环。
程序尽量满足 O(n) 时间复杂度,且仅用 O(1) 内存。
思路描述
两种思路:
1:直接使用两个栈存储从后往前比较,比较到不同,之所以使用栈这种结构是因为他后进先出的特性,这种方法也是最好想到的。
2:使用双指针,说实话这种方法我真没想到,看了题解才明白的,双指针的主要思想是:
- 将两个链表合并
- 创建两个指针
- 如果两个指针的值相同就输出该值,两个指针的值不同就继续循环
- 如果循环到两个指针同时为null那么没有共同节点
当然在实际做的时候只要将第一个链表循环结束时转移到第二个链表的头上就可以实现上述功能
代码
思路一代码:
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
//定义两个栈
Stack<ListNode> s1=new Stack<>();
Stack<ListNode> s2=new Stack<>();
if(headA==null||headB==null){
return null;
}
ListNode pA=headA,pB=headB;
//将两个链表输入到栈中
while(pA!=null){
s1.add(pA);
pA=pA.next;
}
while(pB!=null){
s2.add(pB);
pB=pB.next;
}
//如果两个栈有一个是空的那么无论如何都不会有相交的输出null
if(s1.isEmpty()||s2.isEmpty()){
return null;
}
ListNode aa=s1.pop();//这一步的目的是防止只有一个数相交做一个备份
if(!aa.equals(s2.pop())){
return null;
}
else{
ListNode num=aa;
while(!s1.isEmpty()&&!s2.isEmpty()){
ListNode temp=s1.pop();
//如果不相交了就终止循环,此时num的值还是上次循环产生的值
if(!temp.equals(s2.pop())){
break;
}
num=temp;
}
return num;
}
}
}
这种方法做出来的情况:
可以看出十分不理想主要原因是创建两个栈分别用了M和N的时间,后面的判定是否是相同的值用了i(相同数)的时间,所以时间复杂度为O(M+N+I)
思路二代码:
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if(headA==null||headB==null){
return null;
}
ListNode pA=headA,pB=headB;
while(pA!=null||pB!=null){
if(pA==pB){
return pA;
}
else{
pA=(pA==null)?pA=headB:pA.next;
pB=(pB==null)?pB=headA:pB.next;
}
}
return null;
}
}
由此可看出,的确是栈上面浪费了时间,双指针的方式的确比用栈的方式做更加简单。
写在最后
欢迎大神指正,我会听取并改正!