2014-03-18 02:41

题目:给定一个带有环的单链表,找出环的入口节点。

解法1:用hash来检测重复节点肯定是容易想而且效率也高的好办法。

代码:

 1 // 2.6 You have a circular Linked List: a->b->c->d->e->c. Find where the cycle starts.
 2 #include <cstdio>
 3 #include <unordered_set>
 4 using namespace std;
 5 
 6 struct ListNode {
 7     int val;
 8     ListNode *next;
 9     ListNode(int x): val(x), next(nullptr) {};
10 };
11 
12 class Solution {
13 public:
14     ListNode* firstFirstNodeInCycle(ListNode *head) {
15         if (head == nullptr) {
16             return head;
17         }
18         
19         // hash the pointers.
20         unordered_set<ListNode *> us;
21         ListNode *ptr;
22         
23         ptr = head;
24         while (ptr != nullptr) {
25             if (us.find(ptr) != us.end()) {
26                 // the first node of the cycle is found.
27                 return ptr;
28             } else {
29                 us.insert(ptr);
30                 ptr = ptr->next;
31             }
32         }
33         
34         // the list has no cycle.
35         return nullptr;
36     }
37 };
38 
39 int main()
40 {
41     int i;
42     int n, k;
43     int val;
44     struct ListNode *head, *tail, *ptr;
45     Solution sol;
46     
47     while (scanf("%d", &n) == 1 && n > 0) {
48         // create a linked list
49         ptr = head = tail = nullptr;
50         for (i = 0; i < n; ++i) {
51             scanf("%d", &val);
52             if (head == nullptr) {
53                 head = ptr = new ListNode(val);
54             } else {
55                 ptr->next = new ListNode(val);
56                 ptr = ptr->next;
57             }
58         }
59         tail = ptr;
60         
61         // create a cycle in the list
62         scanf("%d", &k);
63         if (k >= 1 && k <= n) {
64             ptr = head;
65             for (i = 1; i < k; ++i) {
66                 ptr = ptr->next;
67             }
68             tail->next = ptr;
69         }
70         
71         // find the first node in the cycle.
72         ListNode *first_node = sol.firstFirstNodeInCycle(head);
73         if (first_node != nullptr) {
74             printf("%d\n", first_node->val);
75         } else {
76             printf("no cycle\n");
77         }
78         
79         /*
80         // print the list
81         ptr = head;
82         for (i = 0; i < n; ++i) {
83             printf("%d->", ptr->val);
84             ptr = ptr->next;
85         }
86         printf("\n");
87         */
88 
89         // delete the list
90         for (i = 0; i < n; ++i) {
91             ptr = head->next;
92             delete head;
93             head = ptr;
94         }
95     }
96     
97     return 0;
98 }

解法2:如果你非不让我用hash,就只有观察一下几个特殊节点了。既然这个环有“第一个”点,那肯定也有“最后一个”点。我特地打了引号,是因为最后一个点恰好指向第一个。如果你从链表的头开始向后遍历,必然是先到达“第一个”,然后才能到达“最后一个的”。只有对于“最后一个”点,才会出现先到达ptr->next,后到达ptr的情况,所以如果存在符合这个情况的节点ptr,ptr->next就是我们要找的环的入口。这种方法效率不高而且不容易想,除了面试之外基本没有别的用处了。但为了面试淘汰一些人,这点用处也很重要了。

代码:

  1 // 2.6 You have a circular Linked List: a->b->c->d->e->c. Find where the cycle starts.
  2 #include <cstdio>
  3 #include <unordered_set>
  4 using namespace std;
  5 
  6 struct ListNode {
  7     int val;
  8     ListNode *next;
  9     ListNode(int x): val(x), next(nullptr) {};
 10 };
 11 
 12 class Solution {
 13 public:
 14     ListNode* firstFirstNodeInCycle(ListNode *head) {
 15         if (head == nullptr) {
 16             return head;
 17         }
 18         
 19         ListNode *p1, *p2;
 20         
 21         p1 = head;
 22         while (p1 != nullptr) {
 23             p2 = head;
 24             while (p2 != p1->next && p2 != nullptr) {
 25                 if (p2 == p1) {
 26                     break;
 27                 } else {
 28                     p2 = p2->next;
 29                 }
 30             }
 31             if (p2 == p1->next) {
 32                 return p2;
 33             } else {
 34                 p1 = p1->next;
 35             }
 36         }
 37         
 38         return nullptr;
 39     }
 40 };
 41 
 42 int main()
 43 {
 44     int i;
 45     int n, k;
 46     int val;
 47     struct ListNode *head, *tail, *ptr;
 48     Solution sol;
 49     
 50     while (scanf("%d", &n) == 1 && n > 0) {
 51         // create a linked list
 52         ptr = head = tail = nullptr;
 53         for (i = 0; i < n; ++i) {
 54             scanf("%d", &val);
 55             if (head == nullptr) {
 56                 head = ptr = new ListNode(val);
 57             } else {
 58                 ptr->next = new ListNode(val);
 59                 ptr = ptr->next;
 60             }
 61         }
 62         tail = ptr;
 63         
 64         // create a cycle in the list
 65         scanf("%d", &k);
 66         if (k >= 1 && k <= n) {
 67             ptr = head;
 68             for (i = 1; i < k; ++i) {
 69                 ptr = ptr->next;
 70             }
 71             tail->next = ptr;
 72         }
 73         
 74         // find the first node in the cycle.
 75         ListNode *first_node = sol.firstFirstNodeInCycle(head);
 76         if (first_node != nullptr) {
 77             printf("%d\n", first_node->val);
 78         } else {
 79             printf("no cycle\n");
 80         }
 81         
 82         /*
 83         // print the list
 84         ptr = head;
 85         for (i = 0; i < n; ++i) {
 86             printf("%d->", ptr->val);
 87             ptr = ptr->next;
 88         }
 89         printf("\n");
 90         */
 91 
 92         // delete the list
 93         for (i = 0; i < n; ++i) {
 94             ptr = head->next;
 95             delete head;
 96             head = ptr;
 97         }
 98     }
 99     
100     return 0;
101 }

 

 posted on 2014-03-18 02:55  zhuli19901106  阅读(309)  评论(0编辑  收藏  举报