链表 相交结点与环问题

基本问题:

1.两个链表中的第一个公共结点

[解题思路]

a.先求得两个链表的长度,得到链表长度差d

b.根据链表长度差,首先让长链表的指针先走d-1步,之后两个指针一起走,发现相同结点时就是公共结点

    int len1 = 0, len2 = 0;
        ListNode p1 = head1, p2 = head2;
        while (p1 != null) {
            len1++;
            p1 = p1.next;
        }

        while (p2 != null) {
            len2++;
            p2 = p2.next;
        }
        
        ListNode listLong = null, listShort = null;
        int lenDiff = 0; 
        if(len1 > len2){
            listLong = head1;
            listShort = head2;
            lenDiff = len1 - len2;
        } else {
            listLong = head2;
            listShort = head1;
            lenDiff = len2 - len1;
        }
        
        for(int i = 0; i < lenDiff; i++){
            listLong = listLong.next;
        }
        
        while(listLong != null && listShort != null && (listLong != listShort)){
            listLong = listLong.next;
            listShort = listShort.next;
        }

        return listLong;

2.如何判断一个链表中是否存在环

 [解题思路]

和上题类似,维护两个指针,一个指针每次走1步,另一个指针每次走2步,如果快指针追上了慢指针,则链表中存在环

 1 public static boolean checkCircle2(ListNode head) {
 2         if (head == null) {
 3             return false;
 4         }
 5 
 6         ListNode fast = head, slow = head;
 7         while (fast != null && fast.next != null) {
 8             slow = slow.next;
 9             fast = fast.next.next;
10             if(slow == fast){
11                 break;
12             }
13         }
14         return !(fast == null || fast.next == null);
15     }

 

扩展问题:

1.求问题2中环的入口点

 如明确知晓链表中存在环,则在环中将链表拆开,则就变成上面的问题1,找到入口结点之后恢复链表

 1 public static ListNode findPortal(ListNode head) {
 2         if (head == null) {
 3             return null;
 4         }
 5 
 6         ListNode fast = head, slow = head;
 7         ListNode head2 = null, tail = null;
 8         while (fast != null && fast.next != null) {
 9             slow = slow.next;
10             fast = fast.next.next;
11             // meet in circle, break the circle
12             if (slow == fast) {
13                 head2 = fast.next;
14                 tail = fast;
15                 fast.next = null;
16                 break;
17             }
18         }
19 
20         ListNode result = findCommonNode(head, head2);
21         tail.next = head2;
22 
23         return result;
24     }
25 
26     private static ListNode findCommonNode(ListNode head1, ListNode head2) {
27         if (head1 == null || head2 == null) {
28             return null;
29         }
30         int len1 = 0, len2 = 0;
31         ListNode p1 = head1, p2 = head2;
32         while (p1 != null) {
33             len1++;
34             p1 = p1.next;
35         }
36 
37         while (p2 != null) {
38             len2++;
39             p2 = p2.next;
40         }
41         
42         ListNode listLong = null, listShort = null;
43         int lenDiff = 0; 
44         if(len1 > len2){
45             listLong = head1;
46             listShort = head2;
47             lenDiff = len1 - len2;
48         } else {
49             listLong = head2;
50             listShort = head1;
51             lenDiff = len2 - len1;
52         }
53         
54         for(int i = 0; i < lenDiff; i++){
55             listLong = listLong.next;
56         }
57         
58         while(listLong != null && listShort != null && (listLong != listShort)){
59             listLong = listLong.next;
60             listShort = listShort.next;
61         }
62 
63         return listLong;
64     }

 这题还有另外的解题思路:http://www.cppblog.com/humanchao/archive/2012/11/12/47357.html

假设两个指针相遇时slow指针走了s步,则fast指针走了2s步(因为慢指针走一步,快指针走两步)

此时fast指针可能绕环走了n圈(n >= 0), 则有2s = s + nr; ==> s = nr;

设链表起点到环的入口点距离为a,环入口点到两指针相遇点距离为x.==>s = a + x;

==>a + x = nr;

==>a + x = (n-1)r + r

==>a + x = (n-1)r + L - a

==>a = (n-1)r + L - x -a;

则我们在发现fast指针和slow指针相遇时,另外使用两个指针,分别指向链表头结点和相遇结点,同时开始走,则他们相遇结点就是

环的入口结点

 

 1 public static ListNode findPortal2(ListNode head) {
 2         if (head == null) {
 3             return null;
 4         }
 5         
 6         ListNode fast = head, slow = head;
 7         while(fast != null && fast.next != null){
 8             fast = fast.next.next;
 9             slow = slow.next;
10             if(fast == slow){
11                 break;
12             }
13         }
14         
15         if(fast == null || fast.next == null){
16             return null;
17         }
18         
19         ListNode p = head;
20         while(p != fast){
21             p = p.next;
22             fast = fast.next;
23         }
24         return p;
25     }

 

 

 

链表其他问题:

1.求链表倒数第k个结点

2.求链表的中间结点,如链表中结点总数为奇数,返回中间结点;如为偶数,返回中间两个结点的任意一个

问题来源:

http://www.cnblogs.com/sooner/p/3277886.html

posted @ 2013-09-13 14:11  feiling  阅读(371)  评论(0编辑  收藏  举报