206.反转链表
两种方法,一种是迭代法(头插法),一种是递归法。头插法比较简单,就不再多说了,讲下递归法。主要是要注意递归以后head->next指向的是哪个结点,其实head->next的指向是不变的,还是正序第二个,但是逆序以后就是倒数第二个结点了,按照递归的思路需要让这倒数第二个结点指向head结点,所以head->next->next = head,然后记得将head->next置为null,不然会出现环。
83.删除排序链表中的重复元素
两种方法,一种是迭代法,一种是递归法。迭代法就是一前一后两个指针,如果两指针指向的数值相同,就删掉其中一个。递归法得看head的数值和head->next的数值是否相同,如果相同那就删掉head->next,如果不同那就直接返回。
25.K个一组翻转链表
两种方法,一种是迭代法,一种是递归法。迭代法代码长一点,递归法更好写一点。迭代法需要先向后走k步,确保存在这k个结点,然后头插法反转这k个结点,把这段接在之前的处理结果上,如果不足k个结点那就不必反转。递归法看一下是否存在k个结点,如果不存在返回head,如果存在那就对head向后k步的位置递归处理,然后head往后这k个结点头插法反转,最后返回头部指针。
160.相交链表
两种方法,第一种方法是先统计出两链表各自长度,设两个指针,让那个长的链表指针先前进到和短的链表相同的位置,也就是如果链表a长度为5,链表b长度为7,那就先让b指针前进两步,然后a指针和b指针同步前进,返回第一个相同的位置。第二种方法是a指针和b指针同时前进,如果a到头了再从b链表上走一遍,b到头了再从a链表上走一遍,这样a和b最后走的距离相同,而它们走的最后一段就是重合部分,所以一定能同时走到交点位置。
21.合并两个有序链表
两种方法,一种是迭代法,一种是递归法。迭代很简单,设一个尾指针,谁小把谁接过来就行了。递归法就是看下两链表第一个结点谁小,小的那个结点作为新链表的头,然后其余部分递归,返回值就是头部指针,把这个指针连在小的结点后面就行。
143.重排链表
这题是个融合怪,题目要求把a0 -> a1 -> ... -> an变成a0 -> an -> a1 -> an-1 -> ...这样的,可以看到其实就是两个链表一个结点接一个结点拼起来的新链表,首先求出中间位置,然后从中间位置分割为两链表,后面的链表头插一下做个反转,然后和前一个链表交替拼接就好了。
148.排序链表
不管是冒泡、快排、选择都不适合放到链表上用,但是归并貌似很适合链表排序。所以可以按照归并排序来处理,先找到中间位置,然后拆分为两个链表,分别递归下去,最后再把已经排好序的两个链表合并成一个有序链表。
141.环形链表
快慢指针即可,如果快指针遇到了null那就说明无环,如果快慢指针指向相同位置那就说明有环。
19.删除链表的倒数第 N 个结点
维护两个距离为n的同步指针,当前面那个指针走到头了就可以用后面那个指针删了。
23.合并K个升序链表
归并排序的思路,只不过朴素归并中的数组元素被替换成了链表指针,但是做法是一样的,时间复杂度plogq,p是所有链表元素数量加和,q是链表个数。还可以用优先队列去做,时间复杂度也是plogq,只需要自定义优先队列排序规则,使链表首结点值最小的排在队头,然后每次取出队头元素,该元素是个链表,把链表首结点删除剩余部分再次入队即可。
2.两数相加
这题比较简单,直接模拟就行了。
92.反转链表 II
进阶要求一趟扫描,所以这一趟扫描要做到两件事,首先要找到第一段链表尾部指针和第三段链表首部指针,然后就是将第二段进行反转,反转后将三部分拼接就好了,要注意边界条件。
142.环形链表 II
首先先用快慢指针判断是否有环,在确定有环后还需要知道怎么求环的入口位置,可以在快慢指针相遇时让慢指针再跑一圈求出环的长度,然后设置距离为环长的两个同步指针,从起点开始跑,当二者相遇时就是环的入口位置。
82.删除排序链表中的重复元素 II
对于一个元素,是否要删除它可以看它前后两个元素,如果当前元素和前一个或后一个元素值相同,那就应该删除。然后可以转换为往新链表中添加元素的方式,注意最后一个元素的next要置空。
234. 回文链表
先看数据范围,由于链表中数字都是0~9的,所以可以想到把链表上的值转成字符串,然后判断字符串是否回文,可惜运行时会超内存。于是只能换另一种方法,先求下链表长度,然后把链表前一半反转,之后挨个元素比较前一半和后一半对应位置是否相同。另外找链表中点的时候可以用快慢指针来优雅地解决。
24. 两两交换链表中的节点
这题思路本身不难想,观察一下其实可以转化为两个链表的合并,将偶数位置的元素单独摘出来形成一个新链表,然后和剩下元素构成的链表进行合并就好了,但是实现起来出了个bug卡了我好久,主要还是指针操作的顺序没有思考好,写代码前要先在脑海里过一遍,不要想当然。
445. 两数相加 II
先链表反转再相加,然后再反转回去。如果不想反转的话,那可以选择用栈处理。
61. 旋转链表
先求出链表长度len,然后k %= len,接下来就是开两个距离为k的指针,快指针跑到链表尾部时停止,然后把慢指针->next置空,快指针->next置为head就好了。注意一下空链表和k = 0的情况。
328. 奇偶链表
和之前一道题很像,先把偶数位置结点摘出来形成新链表,然后两个链表前后拼接就行了。
138. 复制带随机指针的链表
这题属于知道方法就能秒,但不知道方法的话要想很久。两种方法,第一种是用哈希表存下来原始结点和新建结点之间的映射关系,然后遍历一遍原始链表mp[p]->next = mp[p->next],mp[p]->random = mp[p->random]就结束了。第二种方法是在原始链表的每个结点后面插入新建结点,然后在每个原始结点位置就可以更新它后面挨着的新建结点random指针,最后再把偶数位置结点摘出来就好了。