leetcode:160
编写一个程序,找到两个单链表相交的起始节点。
如下面的两个链表**:**
在节点 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 个节点。
解法1(使用栈解决)
思路:
用栈作为辅助栈,栈的特性"先进后出",那么我们将两个链表放入栈中,遍历出来的第一个肯定是尾节点。那么如果两个链表相交,则肯定从尾节点往前遍历,到相交节点后面的元素肯定都是一样的,所以我们只要比较两个栈中从尾节点开始比较,如果找到不相等的节点,则前节点就是相交的节点;
时间复杂度分析:
遍历到两个栈中,时间复杂度为O(n),两个栈的比较,则是O(m)(m<n),所以整体时间复杂度为O(n)
空间复杂度分析: 因为用到了辅助栈,所以时间复杂度为O(n)
代码:
/**
* 使用栈作为辅助栈的解法
* 用到了辅助栈,时间辅助度为O(m+n)
*
* @param headA
* @param headB
* @return
*/
public static ListNode getIntersectionNode(ListNode headA, ListNode headB) {
// 1.判空
if (headA == null || headB == null) {
return null;
}
// 2.定义两个辅助栈,用来存储两个链表遍历的数据
Stack<ListNode> stackA = new Stack<ListNode>();
Stack<ListNode> stackB = new Stack<ListNode>();
ListNode nodeA = headA;
ListNode nodeB = headB;
// 3.遍历链表,存入栈中
while (nodeA != null) {
stackA.push(nodeA);
nodeA = nodeA.next;
}
while (nodeB != null) {
stackB.push(nodeB);
nodeB = nodeB.next;
}
// 遍历栈中元素进行比较,从尾部开始,找到不同的节点处则返回结果
ListNode pre = null;
while (!stackA.isEmpty() && !stackB.isEmpty()) {
if (stackA.peek() != stackB.peek()) {
return pre;
} else {
pre = stackA.peek();
stackA.pop();
stackB.pop();
}
}
return pre;
}
解法2(优化)
思路:
我们如果可以得到两个链表的长度,那么如果两个链表长度一致的话,两个链表同时从头节点出发同步前进,则当两个节点一样的时候,则是相遇节点;如果两个链表长度不一样长,把长的链表变成跟 比它短的链表一样的长度,即让长的链表先走k步(k= 长链表A - 短链表B),然后两者再一起同步前进即可。
时间复杂度分析:因为需要找到链表的长度,即要遍历链表,则遍历链表A的长度时间复杂度为O(m)(m<n),链表B的长度时间复杂度为O(n),且一起同步的时间复杂度为O(k)(k<n),整体复杂度为O(n)
空间复杂度分析: 没使用其他空间,则为O(1)
代码:
/**
* 优化: 先求出链表的长度,然后让长的链表先走对应的步数,然后再同时走,再进行比较
*
* @param headA
* @param headB
* @return
*/
public static ListNode getIntersectionNode2(ListNode headA, ListNode headB) {
// 1.判空
if (headA == null || headB == null)
return null;
// 2.数组长度
int lengthA = 0;
int lengthB = 0;
ListNode nodeA = headA;
ListNode nodeB = headB;
// 3.求出A/B长度
while (nodeA != null) {
lengthA++;
nodeA = nodeA.next;
}
while (nodeB != null) {
lengthB++;
nodeB = nodeB.next;
}
// 重新赋值
nodeA = headA;
nodeB = headB;
// 4.判断谁的长度比较长,则让它先走
if (lengthA < lengthB) {
int distance = lengthB - lengthA;
for (int i = 0; i < distance; i++) {
nodeB = nodeB.next;
}
}else if(lengthA> lengthB) {
int distance = lengthA - lengthB;
for (int i = 0; i < distance; i++) {
nodeA = nodeA.next;
}
}
// 5. 两者同步前进并比较
while (nodeA != null && nodeB != null) {
if (nodeA == nodeB) {
return nodeA;
}
nodeA = nodeA.next;
nodeB = nodeB.next;
}
return null;
}