相交链表
编写一个程序,找到两个单链表相交的起始节点。
如下面的两个链表:
在节点 c1 开始相交。
例如:

输入: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 个节点。
注意:
如果两个链表没有交点,返回 null.
在返回结果后,两个链表仍须保持原有的结构。
可假定整个链表结构中没有循环。
程序尽量满足 O(n) 时间复杂度,且仅用 O(1) 内存。
思路1
要是能倒推就简单了
5的前一个指针是4
4的前一个指针是8
8的前一个指针有两个:1和1
说明,8是相交结点
问题是,单向链表能找到前一个结点吗?
那就涉及到翻转链表了
正着推
4->1->8->4->5
5->0->1->8->4->5
4跟5
1跟0
8跟1
4跟8
5跟5
null跟5
都不一样,两个链表成了不相交了。这,肯定不对。
思路2
两个链表,找出长度比较短的那个,在前面补-1,使得短的链表长度最后和长的链表长度一样
-1->4->1->8->4->5
5->0->1->8->4->5
然后,再比较
既然是新添加的-1,肯定跟对应的不相等,可直接略过,从不是新添加的地方开始比较。
也就是,直接比较
4->1->8->4->5
0->1->8->4->5
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
//如果两个链表有一个是空,则返回null
if(headA == null || headB == null) return null;
//由于需要保证原结构不变,需要定义新的结点进行操作
ListNode currentNodeHeadA = headA;
ListNode currentNodeHeadB = headB;
//求出链表A的长度
int headALength = 0;
while(currentNodeHeadA != null)
{
currentNodeHeadA = currentNodeHeadA.next;
headALength++;
}
//求出链表B的长度
int headBLength = 0;
while(currentNodeHeadB != null)
{
currentNodeHeadB = currentNodeHeadB.next;
headBLength++;
}
//恢复位置
currentNodeHeadA = headA;
currentNodeHeadB = headB;
if(headALength > headBLength)
{
//A从headALength - headBLength开始
//B从头开始
for(int i = 0; i<headALength - headBLength; i++)
{
currentNodeHeadA = currentNodeHeadA.next;
}
}else{
//B从headBLength - headALength开始
//A从头开始
for(int i = 0; i<headBLength - headALength; i++)
{
currentNodeHeadB = currentNodeHeadB.next;
}
}
while(currentNodeHeadA != null && currentNodeHeadB != null)
{
if(currentNodeHeadA != currentNodeHeadB)
{
currentNodeHeadA = currentNodeHeadA.next;
currentNodeHeadB = currentNodeHeadB.next;
}else{
return currentNodeHeadA;
}
}
return null;
}
}
MJ是更秀
思路3

当判断A链表的某一个节点为null的时候,将B链表拼接到A链表的最后面
同理对B
需要注意的是,如果两个链表不相交,则可能会循环调用。
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
//如果两个链表有一个是空,则返回null
if(headA == null || headB == null) return null;
ListNode currentNodeHeadA = headA;
ListNode currentNodeHeadB = headB;
while(currentNodeHeadA != currentNodeHeadB){
currentNodeHeadA = (currentNodeHeadA == null) ? headB : currentNodeHeadA.next;
currentNodeHeadB = (currentNodeHeadB == null) ? headA : currentNodeHeadB.next;
}
return currentNodeHeadA;
}
}
两个地方需要注意:
错误
currentNodeHeadA = (currentNodeHeadA == null) ? currentNodeHeadB: currentNodeHeadA.next;
currentNodeHeadB = (currentNodeHeadB == null) ? currentNodeHeadA: currentNodeHeadB.next;
拼接的时候,需要拼接是原有的headA或headB
错误
currentNodeHeadA = (currentNodeHeadA.next == null) ? headB : currentNodeHeadA.next;
currentNodeHeadB = (currentNodeHeadB.next == null) ? headA : currentNodeHeadB.next;
使用currentNodeHeadA.next,当两个链表不相交的时候,会循环调用。
分隔链表
题目
给定一个链表和一个特定值 x,对链表进行分隔,使得所有小于 x 的节点都在大于或等于 x 的节点之前。
你应当保留两个分区中每个节点的初始相对位置。
示例:
输入: head = 1->4->3->2->5->2, x = 3
输出: 1->2->2->4->3->5
思路
如果是分隔成两部分,则将结果看成是由两个链表构成,1->2->2 和 4->3->5
然后将两个链表合成一个链表
分隔成三部分,就使用三个链表。
使用链表A,找出比3小的结点
使用链表B,找出比3大或等的结点
之后,将B放在A的末尾
需要注意的是,B的结尾需要手动变为null

class Solution {
public ListNode partition(ListNode head, int x) {
if(head == null) return null;
ListNode leftDummyHead = new ListNode(-1);
ListNode rightDummyHead = new ListNode(-1);
ListNode leftCurrentNode = leftDummyHead;
ListNode rightCurrentNode = rightDummyHead;
while(head != null){
if(head.val < x){
leftCurrentNode.next = head;
leftCurrentNode = leftCurrentNode.next;
}else{
rightCurrentNode.next = head;
rightCurrentNode = rightCurrentNode.next;
}
head = head.next;
}
//需要注意的地方
rightCurrentNode.next = null;
//拼接
leftCurrentNode.next = rightDummyHead.next;
return leftDummyHead.next;
}
}
本文介绍了两种寻找两个单链表相交起始节点的方法。一种是通过调整较短链表来匹配较长链表的长度,另一种是在遍历到链表末端时转向另一个链表头部继续遍历。
5万+

被折叠的 条评论
为什么被折叠?



