面试题系列

  1. 经典面试题 之 单链表找环
  2. 经典面试题 之 数组的循环右移
  3. 经典面试题 之 洗牌问题
  4. 经典面试题 之 在单调矩阵中查找元素
  5. 经典面试题 之 按单词逆序
  6. 经典面试题 之 查字典

大概的题意是,给出一个单向链表的头节点,求这么链表是否有环。有环的定义是,链表的尾节点指向了链接中间的某个节点。单链表的定义如下:

1
2
3
4
struct Node {
    Node(): next(NULL) {}
    Node *next;
};

这道题目还有一些变种,比如求链接的长度,求链表的尾节点等,不过大同小异。第一次听说这个题目,是在大三的时候,从一个刚面完试的学长那里。他当时的做法是对这个链表求逆,求逆的结果链表上每一个指针都反向,如果逆序完之后,链表的头节点不变,即说明链接有环。具体的证明过程略。这个方法的复杂也是O(N),但是需要修改原链表,或者使用O(N)的额外空间。

标准做法是使用两个指针,一个每次往前走2步,一个每次往前走1步,如果两个指针相遇,即说明链表有环,时间复杂度为O(N),空间复杂度为O(1)。

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
bool TestCircle(Node *p){
    if (p == NULL){
        return false;
    }
    if (p->next == NULL){
        return false;
    }
    if (p->next == p){
        return true;
    }

    Node *y = p->next;
    Node *x = p->next->next;

    while(x != NULL && y != NULL){
        x = x->next;
        if (x == NULL) break;
        x = x->next;
        y = y->next;
        if (x == y) break;
    }

    return x == y;
}

测试数据也比较简单,考虑一下空指针、单个节点成环、整条链表成环就可以了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
void RunTest(){
    Node *p = NULL;
    Node *q = NULL;

    cout << "empty list" << endl;
    cout << TestCircle(NULL) << endl;

    cout << "one node not circle" << endl;
    p = new Node;
    cout << TestCircle(p) << endl;
    delete p;
    p = NULL;

    cout << "one node circle" << endl;
    p = new Node;
    p->next = p;
    cout << TestCircle(p) << endl;
    delete p;
    p = NULL;

    cout << "two nodes not circle" << endl;
    p  = new Node;
    p->next = new Node;
    cout << TestCircle(p) << endl;
    delete p->next;
    delete p;
    p = NULL;

    cout << "two nodes circle" << endl;
    p = new Node;
    p->next = new Node;
    p->next->next = p;
    cout << TestCircle(p) << endl;
    delete p->next;
    delete p;
    p = NULL;

    cout << "two nodes circle case 2" << endl;
    p = new Node;
    p->next = new Node;
    p->next->next = p->next;
    cout << TestCircle(p) << endl;
    delete p->next;
    delete p;
    p = NULL;

    cout << "5 nodes not circle" << endl;
    p = new Node;
    q = p;
    for (int i = 0; i < 4; ++i){
        q->next = new Node;
        q = q->next;
    }
    cout << TestCircle(p) << endl;
    while(p->next != NULL){
        q = p->next->next;
        delete p->next;
        p->next = q;
    }
    delete p;
    p = NULL;

    cout << "5 nodes circle" << endl;
    p = new Node;
    q = p;
    for (int i = 0; i < 4; ++i){
        q->next = new Node;
        q = q->next;
    }
    q->next = p;
    cout << TestCircle(p) << endl;
    q->next = NULL;
    while(p->next != NULL){
        q = p->next->next;
        delete p->next;
        p->next = q;
    }
    delete p;
    p = NULL;

    cout << "5 nodes circle case 2" << endl;
    p = new Node;
    q = p;
    for (int i = 0; i < 4; ++i){
        q->next = new Node;
        q = q->next;
    }
    q->next = p->next->next;
    cout << TestCircle(p) << endl;
    q->next = NULL;
    while(p->next != NULL){
        q = p->next->next;
        delete p->next;
        p->next = q;
    }
    delete p;
    p = NULL;

    cout << "5 nodes circle case 3" << endl;
    p = new Node;
    q = p;
    for (int i = 0; i < 4; ++i){
        q->next = new Node;
        q = q->next;
    }
    q->next = q;
    cout << TestCircle(p) << endl;
    q->next = NULL;
    while(p->next != NULL){
        q = p->next->next;
        delete p->next;
        p->next = q;
    }
    delete p;
    p = NULL;

    cout << "100000000 nodes not circle" << endl;
    p = new Node;
    q = p;
    for (int i = 0; i < 100000000; ++i){
        q->next = new Node;
        q = q->next;
    }
    cout << TestCircle(p) << endl;
    while(p->next != NULL){
        q = p->next->next;
        delete p->next;
        p->next = q;
    }
    delete p;
    p = NULL;

    cout << "100000000 nodes circle" << endl;
    p = new Node;
    q = p;
    for (int i = 0; i < 100000000; ++i){
        q->next = new Node;
        q = q->next;
    }
    q->next = p;
    cout << TestCircle(p) << endl;
    q->next = NULL;
    while(p->next != NULL){
        q = p->next->next;
        delete p->next;
        p->next = q;
    }
    delete p;
    p = NULL;

    cout << "100000000 nodes circle case 2" << endl;
    p = new Node;
    q = p;
    for (int i = 0; i < 100000000; ++i){
        q->next = new Node;
        q = q->next;
    }
    Node *t = p;
    for (int i = 0; i < 16; ++i){
        t = t->next;
    }
    q->next = t;
    cout << TestCircle(p) << endl;
    q->next = NULL;
    while(p->next != NULL){
        q = p->next->next;
        delete p->next;
        p->next = q;
    }
    delete p;
    p = NULL;
}

您还可能感兴趣的日志:

  1. 经典面试题 之 单链表找环
  2. 经典面试题 之 数组的循环右移
  3. 经典面试题 之 洗牌问题
  4. 经典面试题 之 按单词逆序
  5. 经典面试题 之 在单调矩阵中查找元素
  6. unordered_map
  7. C#中重载相等运算符
  8. 在C语言中使用MSXML
  9. 检测本机安装的MSXML的版本的方法
  10. Hyper-V的自动化 (0) 远程连接

 Leave a Reply

(required)

(required)

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

   
© 2004 - 2011 Leona+Suffusion theme by Sayontan Sinha