1. 判断两个均不含有环的单链表是否相交——编程之美3.6
两个没有环的链表相交于一节点,则在这个节点之后的所有结点都是两个链表所共有的。如果它们相交,则最后一个结点一定是共有的,则只需要判断最后一个结点是否相同即可。时间复杂度为O(len1+len2)。
struct Node { int data; Node *next; }; bool isCross(Node *head1, Node *head2) { Node *p1 = head1, *p2 = head2; while (p1->next) p1 = p1->next; while (p2->next) p2 = p2->next; return p1 == p2; }
对于相交的第一个结点,则可求出两个链表的长度,然后用长的减去短的得到一个差值 K,然后让长的链表先遍历K个结点,然后两个链表再开始遍历,进行比较,第一个相等的指针为目标节点。
2. 判断链表是否存在环
可以设置两个指针fast和slow,初始均指向头结点,slow每次向前一步,fast每次向前两步;如果链表中有环,则fast先进入环中,而slow后进入环中,两个指针在环中必定相遇;如果fast遍历到尾部为NULL,则无环。
bool isExitsLoop(Node *head) { if (head == NULL) return 0; Node *slow = head, *fast = head; while (fast && fast->next) { slow = slow->next; fast = fast->next->next; if (slow == fast) return 1; } return 0; }
3. 如果链表为存在环,如何找到环的入口点?
当fast与slow相遇时,slow肯定没有走遍历完链表,而fast已经在环内循环了n圈(1<=n)。假设slow走了s步,则fast走了2s步(fast步数还等于s 加上在环上多转的n圈),设环长为r,则:
2s = s + nr
s= nr
设整个链表长L,入口环与相遇点距离为x,起点到环入口点的距离为a。
a + x = nr
a + x = (n – 1)r +r = (n-1)r + L - a
a = (n-1)r + (L – a – x)
(L – a – x)为相遇点到环入口点的距离,由此可知,从链表头到环入口点等于(n-1)循环内环+相遇点到环入口点
因而,可以在链表头,相遇点分别设定一个指针,每次各走一步,两个指针必定相遇,且第一个相遇点为环入口点。
Node *findLoopPort(Node *head) { Node *slow = head, *fast = head; while (fast && fast->next) { slow = slow->next; fast = fast->next->next; if (slow == fast) break; } if (fast || fast->next) return NULL; slow = head; while (slow != fast) { slow = slow->next; fast = fast->next; } return slow; }
4. 现在也可以解决第1个问题的入口点问题:如果链表不含有环,如何找到第一个不相交的结点?
将问题转化为上一个问题:将第二个链表首尾相连,然后判断第一个链表是否有环,如果有,则它们必然相交,否则不相交。如何找到相交的首个节点呢?其实也就是第一个链表的环的入口节点。
Node *findPort(Node *head1, Node *head2) { Node *tail2 = head2; while (tail2->next) tail2 = tail2->next; tail2->next = head2;//给单链表建环 Node *temp = findLoopPort(head1); tail2->next = NULL;//给单链表解环 return temp; }
5. 删除非头结点单链表的指定节点(只给定待删除节点指针)——编程之美3.4
随机给出单链表中一个非头节点或者尾节点,删除该节点,当传入空节点时,返回 。
思路:由于没有头节点,非循环单链表,无法获取目标节点的前一节点,所以只能把它的next节点数据前移,并删除next节点。
void deleteRandomNode(Node *pCur) { assert(pCur != NULL); Node *pNext = pCur->next; if (pNext != NULL) { pCur->next = pNext->next; pCur->data = pNext->data; delete pNext; } }