目录
题目描述
输入两个链表,找出他们的第一个公共节点。
链表节点定义如下:
/** * 链表节点 * @Author rex * 2018/9/4 */ public class ListNode { int value; ListNode next; }
测试用例
- 功能测试(输入的两个链表有公共节点:第一个公共节点在链表的中间,第一个公共节点在链表的尾部,第一个公共节点是链表的头节点;输入的两个链表没有公共节点)
- 特殊输入测试(输入的链表头节点是空指针)
题目考点
- 考察应聘者对时间复杂度和空间复杂度的理解及分析能力。解决这道题有多种不同的思路。每当应聘者想到一种思路的时候,都要很快分析出这种思路的时间复杂度和空间复杂度各是多少,并找到可以优化的地方。
- 考察应聘者对链表的编程能力。
解题思路
首先我们要联想到这样一张图:
然后我们就会有下面的解法:
用栈解题
对于上面那张图,我们会想到我们只要从链表的尾部开始遍历。那么最后一个相同的节点就是我们要找的节点。但是单向链表不能从尾开始遍历,所以我们要借助栈的后进先出特点来实现从尾部遍历,。
这种算法:时间复杂度为O(m+n),空间复杂度也是O(m+n)
规律解题
我们可以先遍历出他们的长度,他们的长度之差就是长的链表需要先走的步数。长链表先走完长度之差,他们就可以同时开始遍历了,直到他们遇到第一个相同的节点。
这种算法:时间复杂度是O(m+n),空间复杂度为O(1)
参考解题
用栈解题
import java.util.Deque;
import java.util.ArrayDeque;
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}*/
public class Solution {
// 栈,先进后出
public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
// 异常
if(pHead1 == null || pHead2 == null){
return null;
}
// JDK建议双向队列Deque优先于Stack
Deque<ListNode> s1= new ArrayDeque<>();
Deque<ListNode> s2= new ArrayDeque<>();
ListNode commonNode = null;
// 链表入栈
while (pHead1 != null) {
s1.push(pHead1);
pHead1 = pHead1.next;
}
while (pHead2 != null) {
s2.push(pHead2);
pHead2 = pHead2.next;
}
// 逐个弹出栈顶元素比较,commonNode储存同节点
while(!s1.isEmpty() && !s2.isEmpty()){
if(s1.peek() == s2.peek()){
commonNode = s1.peek();
}
s1.pop();
s2.pop();
}
//
return commonNode;
}
}
规律解题
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}*/
public class Solution {
// 长度规律解题
public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
// 异常
if(pHead1 == null || pHead2 == null){
return null;
}
// --------获取长度、长度差--------------
int lengthL1 = getLength(pHead1);
int lengthL2 = getLength(pHead2);
int lengthDf = Math.abs(lengthL1 - lengthL2);
// --------按照规律遍历------------------
ListNode longListHead = pHead1;
ListNode shortListHead = pHead2;
if(lengthL2 > lengthL1){
longListHead = pHead2;
shortListHead = pHead1;
}
// 长链表先走长度之差步
for(int i = 0; i < lengthDf; ++i){
longListHead = longListHead.next;
}
// 然后两条链表同时走
while((longListHead != null) && (shortListHead != null) && (longListHead != shortListHead)){
// 当前节点不为空,当前节点不相同,则遍历
longListHead = longListHead.next;
shortListHead = shortListHead.next;
}
// 第一个公共节点
ListNode firstCommonNode = longListHead;
return firstCommonNode;
}
// 功能函数,获取链表长度
public int getLength(ListNode pHead){
// 异常
if(pHead == null){
return 0;
}
ListNode pNode = pHead;
int length = 0;
while(pNode != null ){
// 当前节点不为空,则遍历
++length;
pNode = pNode.next;
}
return length;
}
}