《Cracking the Coding Interview》——第2章:链表——题目6

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 }

 

你可能感兴趣的:(interview)