今天的内容依然是链表相关的操作
两两交换链表的节点,删除链表的倒数第n个节点,链表相交和环形链表。
1. 两两交换链表的节点
首先是交换链表节点。链表基本操作的运用,不算很难。注意使用dummyhead来存储一个始终指向链表头指针的指针,方便在修改链表之后返回dummyhead->next 来返回链表结果。注意在判例时先判断cur->next,否则会在cur->next->next发生空引用错误。leetcode删除缓存会报错,就不用这步操作了。
题例: 24 两两交换链表的节点
要先想好dummyhead在链表中能起到的作用,再去解决问题。否则容易在遍历条件上出现错误。
2. 删除链表的倒数第n个节点
这也是变相的链表基本操作。第一反应的暴力解法思路是遍历一遍链表得到链表长度size,再找到size-n+1的位置删除。测试下来暴力算法是可以通过的。
使用双指针法,让快指针先移动n次,慢指针再跟随一起移动,就可以一次遍历找到删除位置。
有一点需要注意,删除节点时要令指针指向期望删除节点的上一个节点,否则删除的位置会出错。
题例: 19 删除链表倒数第n个节点
3. 链表相交
链表相交,指的是链表的节点指向同一个内存,而不是值相同。
两个链表若相交,则从交点开始到尾节点是合并的。第一反应的解法是,对齐尾节点,从短的一条链表开始遍历找到第一个指向相同内存的节点。按照这个思路,首先需要遍历两个链表的长度,然后让长链表指针先移动到短链表开始处开始同步遍历。
if (lenB > lenA) {
swap (lenA, lenB);
swap (curA, curB);
}
使用swap的方式可以简化对lenA和lenB长度的比较。在不需要操作链表节点的时候,直接比较curA,curB更方便。也不需要设dummyhead;
题例: 面试题 02.07. 链表相交
4. 环形链表
环形链表即链表的尾节点不指向NULL而是指向链表的一个节点。那么要检验一个链表是否是环形链表,我的思路是利用追逐的方式,慢指针移动一次时快指针移动两次,如果在某一时刻快指针和慢指针指向同一个节点,那么链表就是环形的。但是链表并不一定是首尾相连的,所以相遇的时候不一定是在交点上。
起点到相遇点的长度,是起点到相遇,再在循环体内循环一次的长度和的一半,快指针实际上多走了一个循环的长度,也就是说循环的长度等于起点到相遇点的长度,计算可得起点到交点的长度,等于相遇点到交点的长度。
题例: 142. 环形链表 II
这道题目的测试用例很刁钻,在指针判例的时候一定要注意,fast,fast->next,fast->next->next都要判空,否则会有空链表导致空引用。需要小心谨慎。