链表操作在面试中会经常出现,下面列举的链表操作方法是比较典型的。
问题1:输入一个单向链表,输出该链表中倒数第k个结点
一个单向链表无法像数组一样可以直接索引,那么要找到链表的倒数第K个节点该怎么操作呢,其实思路非常简单,我们只需要设置两个指针p1,p2,首先p1和p2都指向链表的头部head,然后p2向前走k步,这样p1和p2之间就间隔k个节点,最后p1和p2同时向前移动,直至p2走到链表末尾,然后返回p1就是我们要找的链表的倒数K个节点。
01 | struct ListNode{ |
02 | char data; |
03 | ListNode *next; |
04 | }; |
05 | ListNode *head, *p1, *p2; |
06 | ListNode *func(ListNode *head, int k){ |
07 | assert (k>=0); //保证k应该要大于0 |
08 | p1 = p2 = head; |
09 | for (; k>0; k--) |
10 | p2 = p2->next; //移动p2到与p1距离k个位置 |
11 | if (k>0) |
12 | return //要考虑到链表的元素可以小于k个 |
13 | while (p2!=NULL){ |
14 | p2 = p2->next; |
15 | p1 = p1->next; //移动p1,p2直到p2到达最后 |
16 | } |
17 | return p1; |
18 | } |
问题2:如何判断一个链表有环
这个问题可以这么来分析我们可以设置两个指针(p1, p2),初始值都指向头,p1每次前进一步,p2每次前进二步,如果链表存在环,则p2先进入环,p1后进入环,两个指针在环中走动,必定相遇,如何两节点相遇说明了这个链表存在一个环,以此思路给出了一下代码片段:
01 | struct Node{ |
02 | int data; |
03 | Node *next; |
04 | } |
05 | bool isCircle(Node *head, Node *CircleNode, Node *lastNode){ |
06 | Node *fast = head->next; //步长为2的节点 |
07 | Node *slow = head; //步长为1的节点 |
08 | while (fast != slow && fast && slow){ //当两节点不相遇且还未到达末尾时进行循环 |
09 | if (fast->next != NULL) |
10 | fast = fast->next; |
11 | if (fast->next ==NULL) |
12 | lastNode = fast; //记录尾节点 |
13 | if (slow->next = NULL) |
14 | lastNode = slow; //记录尾节点 |
15 | fast = fast->next; |
16 | slow= slow->next; |
17 | } |
18 | if (fast == slow && fast && slow){ |
19 | CircleNode = fast; //记录相遇的节点 |
20 | return True; |
21 | } |
22 | else |
23 | return false ; |
24 | } |
问题3:如何判断两个链表是否相交
分析:问题可以分为两种情况,第一种情况如果两个链表都没有环的话,那么两个链表要是相交,那么从他们相交的那一点开始到尾节点两个链表应该完全相同,这样我们就可以直接判断链表的尾节点是否相同来进行判断两链表是否相交来进行判断。第二种情况的话如果两个链表存在环的话,那么我们则应该判断一链表上俩指针相遇的那个节点,在不在另一条链表上,如果在,则相交,如果不在,则不相交。由此可给出下面的代码片段:
01 | bool detect(Node *head1, Node *head2){ |
02 | Node *circleNode1; //链表1的相交节点 |
03 | Node *circleNode2; //链表2的相交节点 |
04 | Node *lastNode1; //链表1的尾节点 |
05 | Node *lastNode2; //链表2的尾节点 |
06 | bool isCircle1 = isCircle(head1, circleNode1, lastNode1); //判断链表1是否存在环 |
07 | bool isCircle2 = isCircle(head2, circleNode2, lastNode2); //判断链表2是否存在环 |
08 | if (isCircle1 != isCircle2) |
09 | return false ; |
10 | else if (!isCircle1 && !isCircle2){ //如果两链表都不存在环可以直接对尾节点进行比较看是否相交 |
11 | return lastNode1 == lastNode2; |
12 | } |
13 | else { //如果连链表都存在环的话要看相交节点是不是在两链表都出现 |
14 | Node *temp = circleNode1->next; |
15 | while (temp != circleNode1){ |
16 | if (temp == circleNode2) |
17 | return true ; |
18 | temp = temp->next; |
19 | } |
20 | return false ; |
21 | } |
22 | return false ; |
23 | } |