本节重点:主要包含链表相关算法。

总结:

1、链表翻转是基本操作

  • k个一组翻转列表

3、node.next.next的使用

  • 归并排序。
  • 判断是否有环

4、交叉链表的第一个节点的快速解法。

4、编码模板

  • 需要判断head为null
  • 双指针pre和current。一般步长为1,有的时候需要设置步长。
  • 新建一个链表,还需要一个tail指针,用来在新链表上追加节点

 

1 链表节点

1、节点定义

 

2、打印节点

2 链表翻转

2.1 翻转

反转一个单链表。

示例:

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/reverse-linked-list/

算法:

2.2 两两交互链表中元素

算法:

给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。

你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

示例:

给定 1->2->3->4, 你应该返回 2->1->4->3.

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/swap-nodes-in-pairs

算法:这里使用了tail、pre、current三个指针,注意三个指针在移动过程中设置。

2.3 K 个一组翻转链表

给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。

k 是一个正整数,它的值小于或等于链表的长度。

如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。

示例:

给你这个链表:1->2->3->4->5

当 k = 2 时,应当返回: 2->1->4->3->5

当 k = 3 时,应当返回: 3->2->1->4->5

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/reverse-nodes-in-k-group

算法:使用步长双指针,按步长截断之后,翻转,再拼接到新的链表上

2.4  指定M到N的节点翻转

反转从位置 m 到 n 的链表。请使用一趟扫描完成反转。

说明:
1 ≤ m ≤ n ≤ 链表长度。

示例:

输入: 1->2->3->4->5->NULL, m = 2, n = 4
输出: 1->4->3->2->5->NULL

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/reverse-linked-list-ii

算法:查找m和n的位置切分为三个链表,然后翻转m到n链表,再和原来表进行拼装。

2.5 旋转K个元素

给定一个链表,旋转链表,将链表每个节点向右移动 k 个位置,其中 k 是非负数。

示例 1:

输入: 1->2->3->4->5->NULL, k = 2
输出: 4->5->1->2->3->NULL
解释:
向右旋转 1 步: 5->1->2->3->4->NULL
向右旋转 2 步: 4->5->1->2->3->NULL

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/rotate-list

算法:

  • 旋转过程可以理解为:从k+1的位置拆分成两个链表,再拼接

 

3 排序

3.1 链表进行插入排序

对链表进行插入排序。https://leetcode-cn.com/problems/insertion-sort-list/

算法:

  • 判断head是否为null
  • 排序insert函数要有返回类型,不能是void.
  • 每个节点进行插入排序时,需要设置next指针为null

 

 

3.2 输出奇偶排序链

原始链表:5 -> -3  -> 6 -> 2 -> 4

输出:

奇数链表 -3 -> 5

偶数链表  2 -> 4 -> 6

算法:使用 链表的插入排序。

代码:

  • 判断head是否为null
  • 奇数判断,if (node.val % 2 != 0),不能是if (node.val % 2 == 1)。
  • insert()逻辑中添加了 初始化时这个节点为null 情况。

 

3.3  归并排序O(n log n

在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序。

链接:https://leetcode-cn.com/problems/sort-list/

算法思想:

  • 分割。通过next.next指针操作实现了查找数组mid的操作。
  • 中止条件  current !=null && current.next != null
  • pre=pre.next执行条件是current !=null && current.next != null

4 对折链表

4.1 对折之后打印(从右到左)

给定一个单链表 L:L0→L1→…→Ln-1→Ln ,
将其重新排列后变为: L0→Ln→L1→Ln-1→L2→Ln-2→…

你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/reorder-list

算法:

  • 判断head是否为null
  • 将链表转换为list,然后两个指针输出。
  • 采用count的作为中止条件,不需要再比较left和right指针了

4.2 对折之后打印 (从左到有)

链表从中间对折后左右依次打印,效果:

1->2->3->4->5

3 2 4 1 5

算法:

  • 判断head是否为null
  • 将链表转换为list,然后两个指针输出。
  • 采用count的作为中止条件,不需要再比较left和right指针了

 

5 链表删除节点

5.1 删除指定点

删除链表中等于给定值 val 的所有节点。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/remove-linked-list-elements/

示例:

算法:

  • 判断head是否为null
  • 最后再处理head节点。

 

5.2 通过值拷贝删除

请编写一个函数,使其可以删除某个链表中给定的(非末尾)节点。传入函数的唯一参数为 要被删除的节点 。

输入:head = [4,5,1,9], node = 5
输出:[4,1,9]
解释:给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9.

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/delete-node-in-a-linked-list

算法:因为无法获取node的pre指针,通过值拷贝来实现。

 

6 遍历节点

6.1 倒数第k个节点

6.1.1 输出导出第K个节点

输入一个链表,输出该链表中倒数第k个节点。为了符合大多数人的习惯,本题从1开始计数,即链表的尾节点是倒数第1个节点。例如,一个链表有6个节点,从头节点开始,它们的值依次是1、2、3、4、5、6。这个链表的倒数第3个节点是值为4的节点。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/lian-biao-zhong-dao-shu-di-kge-jie-dian-lcof

算法:使用双指针,两个指针针步长为k。

6.1.2 删除倒数第K个节点

给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。

示例:

给定一个链表: 1->2->3->4->5, 和 n = 2.

当删除了倒数第二个节点后,链表变为 1->2->3->5.

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/remove-nth-node-from-end-of-list
算法:

  • 需要考虑是head节点情况。

6.2 环

6.2.1 是否存环

给定一个链表,判断链表中是否有环。

为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。

示例 1:

输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/linked-list-cycle

解法1 双指针next.next

算法:通过两个指针来实现,一个步长是node.next。一个是node.next.next。

解法2 通过HashSet记录访问节点

6.2.2  查找环第一个节点

给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。

为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/linked-list-cycle-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

算法:通过map保存节点路径信息。

 

6.3 链表交叉

6.3.1  两个链表第一个交点

输入两个链表,找出它们的第一个公共节点。

链接:https://leetcode-cn.com/problems/liang-ge-lian-biao-de-di-yi-ge-gong-gong-jie-dian-lcof/

解法1 :借助于set来完成

解法2  路径相等

7 合并链表

7.1 合并两个有序链表

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

示例:

输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/merge-two-sorted-lists

算法:

  • 新节点需要初始化下

7.2 合并k个有序链表

给你一个链表数组,每个链表都已经按升序排列。

请你将所有链表合并到一个升序链表中,返回合并后的链表。

示例 1:

输入:lists = [[1,4,5],[1,3,4],[2,6]]
输出:[1,1,2,3,4,4,5,6]
解释:链表数组如下:
[
1->4->5,
1->3->4,
2->6
]
将它们合并到一个有序链表中得到。
1->1->2->3->4->4->5->6

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/merge-k-sorted-lists
算法:使用归并处理,分而治之。使用了7.1合并两个有序链表操作

 

8 运算

8.1 两数相加

给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。

示例:

输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8
原因:342 + 465 = 807

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/add-two-numbers

代码:

  • 新建一个链表时,需要定义一个head和tail。tail在追加操作时使用
  • 注意while条件

 

8.2 两数求和

给你两个 非空 链表来代表两个非负整数。数字最高位位于链表开始位置。它们的每个节点只存储一位数字。将这两数相加会返回一个新的链表。

你可以假设除了数字 0 之外,这两个数字都不会以零开头。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/add-two-numbers-ii

算法:首先翻转两个输入链表(2.1) ;然后利用8.1两个数之和; 翻转结果。

 

分类&标签