您的位置:首页 > 其它

单链表的交集

2016-12-26 00:00 281 查看

原题

  Write a program to find the node at which the intersection of two singly linked lists begins.
  For example, the following two linked lists:

A:          a1 → a2
↘
c1 → c2 → c3
↗
B:     b1 → b2 → b3


  begin to intersect at node c1.
  Notes:
  If the two linked lists have no intersection at all, return null.
  The linked lists must retain their original structure after the function returns.
  You may assume there are no cycles anywhere in the entire linked structure.
  Your code should preferably run in O(n) time and use only O(1) memory.

题目大意

  找两个单链表的交集部分。
  如果没有交集返回null。
  函数操作后,单链表必须返回他们原来的结构。
  假定整个链表中没有环。
  函数必须在O(N)时间复杂度,O(1)空间复杂度以内完成。

解题思路

  先将其中一个链表的链头按到另一个链表的尾部,如果他们有交集则会构成一个环,题目等价于找链表中的环的起始结点。找到后将链表还原。

代码实现

结点类

public class ListNode {
int val;
ListNode next;
ListNode(int x) {
val = x;
next = null;
}
}


算法实现类

public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {

if (headA == null || headB == null) {
return null;
}

ListNode ta; // 用于记录headA链表的尾结点
ListNode ha = headA;

// 第一步、找到headA的尾结点
while (ha.next != null) {
ha = ha.next;
}

ta = ha; // 记录链表headA的尾结点

// 第二步、将headB接到ta后面
ta.next = headB;

// 第三步、判断是否存在环
// 判断链表是否存在环,办法为:
// 设置两个指针(fast, slow),初始值都指向头,slow每次前进一步,fast每次前进二步,
// 如果链表存在环,则fast必定先进入环,而slow后进入环,两个指针必定相遇。
// (当然,fast先行头到尾部为NULL,则为无环链表)程序如下:

ListNode fast = headA; // 每次前进一步
ListNode slow = headA; // 每次前进二步
while (fast != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;

if (fast == slow) { // 如果相遇了就退出来
break;
}
}

// 没有环的情况
if (fast == null || fast.next == null) {
ta.next = null; // 解开拼接好的链表
return null;
}

// 有环的情况
// 找到环的入口点
// 当fast若与slow相遇时,slow肯定没有走遍历完链表,而fast已经在环内循环了n圈(1<=n)。
// 假设slow走了s步,则fast走了2s步(fast步数还等于s 加上在环上多转的n圈),设环长为r,则:
//
// 2s = s + nr
// s= nr
//
// 设整个链表长L,入口环与相遇点距离为x,起点到环入口点的距离为a。
// a + x = nr
// a + x = (n – 1)r +r = (n-1)r + L - a
// a = (n-1)r + (L – a – x)
//
// (L – a – x)为相遇点到环入口点的距离,由此可知,从链表头到环入口点等于(n-1)循环内环+相遇点到环入口点,
// 于是我们从链表头、与相遇点分别设一个指针,每次各走一步,两个指针必定相遇,且相遇第一点为环入口点。
slow = headA;
while (slow != fast) {
fast = fast.next;
slow = slow.next;
}

ta.next = null;
return slow;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: