本系列为Leetcode刷题笔记,刷题平台为Leetcode中文站, 刷题按Tag分类。本系列题解汇总如下 (持续更新…):
本文主要是链表相关题目题解总结。
[TOC]
链表
2. 两数相加
题目描述
给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。
如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。
您可以假设除了数字 0 之外,这两个数都不会以 0 开头。
示例:1
2
3输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8
原因:342 + 465 = 807
解题思路
设置哨兵节点,每次新建节点保存当前位的值,并将进位给下一次迭代用。
| 1 | # Definition for singly-linked list. | 
19. 删除链表的倒数第N个节点
题目描述
给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
示例:1
2
3给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.
说明:
给定的 n 保证是有效的。
进阶:
你能尝试使用一趟扫描实现吗?
解题思路
新建伪结点,先让原指针走n步,寻找到删除的位置,然后一起遍历,原指针走到尾了,伪指针走到要删除节点的前一个,将伪指针的下一个节点跳过。
| 1 | # Definition for singly-linked list. | 
| 1 | class ListNode { | 
21. 合并两个有序链表
题目描述
将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例:1
2输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4
解题思路
| 1 | # Definition for singly-linked list. | 
23. 合并K个排序链表
题目描述
合并 k 个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。
示例:1
2
3
4
5
6
7输入:
[
  1->4->5,
  1->3->4,
  2->6
]
输出: 1->1->2->3->4->4->5->6
解题思路
分治+归并1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution(object):
    def mergeKLists(self, lists):
        """
        :type lists: List[ListNode]
        :rtype: ListNode
        """
        
        if len(lists) == 0:
            return None
        if len(lists) == 1:
            return lists[0]
        
        mid = len(lists) // 2
        left = self.mergeKLists(lists[:len(lists)//2])
        right = self.mergeKLists(lists[len(lists)//2:])
        return self.merge(left, right)
    
    def merge(self, left, right):
        if not left:
            return right
        if not right:
            return left
        dummy = ListNode(0)
        pre = dummy
        while left and right:
            if left.val < right.val:
                pre.next = left
                left = left.next
            else:
                pre.next = right
                right = right.next
            pre = pre.next
        pre.next = left if left else right
        
        return dummy.next
24. 两两交换链表中的节点
题目描述
给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。
示例:1
给定 1->2->3->4, 你应该返回 2->1->4->3.
说明:
你的算法只能使用常数的额外空间。
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
解题思路
设置头节点,向后遍历。
| 1 | # Definition for singly-linked list. | 
| 1 | class ListNode { | 
25. K 个一组翻转链表
题目描述
给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。
k 是一个正整数,它的值小于或等于链表的长度。
如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。
示例 :1
2
3
4
5给定这个链表:1->2->3->4->5
当 k = 2 时,应当返回: 2->1->4->3->5
当 k = 3 时,应当返回: 3->2->1->4->5
说明 :
你的算法只能使用常数的额外空间。
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
解题思路
求出翻转的次数+对每一次进行反转
| 1 | # Definition for singly-linked list. | 
61. 旋转链表
题目描述
给定一个链表,旋转链表,将链表每个节点向右移动 k 个位置,其中 k 是非负数。
示例 1:1
2
3
4
5输入: 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
示例 2:1
2
3
4
5
6
7输入: 0->1->2->NULL, k = 4
输出: 2->0->1->NULL
解释:
向右旋转 1 步: 2->0->1->NULL
向右旋转 2 步: 1->2->0->NULL
向右旋转 3 步: 0->1->2->NULL
向右旋转 4 步: 2->0->1->NULL
解题思路
先求链表长度,当k>length时,k对length求余,然后将链表后k个移到开头;使用快慢指针的方法找到后面k个节点。
| 1 | # Definition for singly-linked list. | 
82. 删除排序链表中的重复元素 II
题目描述
给定一个排序链表,删除所有含有重复数字的节点,只保留原始链表中 没有重复出现 的数字。
示例 1:1
2输入: 1->2->3->3->4->4->5
输出: 1->2->5
示例 2:1
2输入: 1->1->1->2->3
输出: 2->3
解题思路
要删除重复的节点,而头节点就有可能是重复的节点,因此新建头节点,同样的值略过。
| 1 | # Definition for singly-linked list. | 
83. 删除排序链表中的重复元素
题目描述
给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次。
示例 1:1
2输入: 1->1->2
输出: 1->2
示例 2:1
2输入: 1->1->2->3->3
输出: 1->2->3
解题思路
每次迭代判断当前节点和下一节点是否相等,若相等,该节点的下个节点等于下个节点的下个节点,相当于下个节点和当前节点相等,就跳过下个节点。
当当前节点和下一节点不相等时,当前节点往前走,判断下一节点。
| 1 | # Definition for singly-linked list. | 
86. 分隔链表
题目描述
给定一个链表和一个特定值 x,对链表进行分隔,使得所有小于 x 的节点都在大于或等于 x 的节点之前。
你应当保留两个分区中每个节点的初始相对位置。
示例:1
2输入: head = 1->4->3->2->5->2, x = 3
输出: 1->2->2->4->3->5
解题思路
用两个指针,分别保存比x小的及比x大的值,对原链表进行遍历根据值的大小拼接在相应的链表后面,最后在把两个链表拼接在一起就可以了。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution(object):
    def partition(self, head, x):
        """
        :type head: ListNode
        :type x: int
        :rtype: ListNode
        """
        if not head or not head.next:
            return head
        
        dummy = ListNode(0)
        pre = dummy
        larger = ListNode(0)
        temp = larger
        
        while head:
            if head.val < x:
                pre.next = head
                pre = pre.next
            else:
                node = ListNode(head.val)
                temp.next = node
                temp = temp.next
            head = head.next
            
        pre.next = larger.next
        return dummy.next
92. 反转链表 II
题目描述
反转从位置 m 到 n 的链表。请使用一趟扫描完成反转。
说明:
1 ≤ m ≤ n ≤ 链表长度。
示例:1
2输入: 1->2->3->4->5->NULL, m = 2, n = 4
输出: 1->4->3->2->5->NULL
解题思路
| 1 | # Definition for singly-linked list. | 
| 1 | # Definition for singly-linked list. | 
109. 有序链表转换二叉搜索树
题目描述
给定一个单链表,其中的元素按升序排序,将其转换为高度平衡的二叉搜索树。
本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。
示例:1
2
3
4
5
6
7
8
9给定的有序链表: [-10, -3, 0, 5, 9],
一个可能的答案是:[0, -3, 9, -10, null, 5], 它可以表示下面这个高度平衡二叉搜索树:
      0
     / \
   -3   9
   /   /
 -10  5
解题思路
将链表转换为数组,然后构建二叉搜索树。
| 1 | # Definition for singly-linked list. | 
138. 复制带随机指针的链表
题目描述
给定一个链表,每个节点包含一个额外增加的随机指针,该指针可以指向链表中的任何节点或空节点。
要求返回这个链表的深度拷贝。
解题思路
首先复制label和next指针,然后复制random指针,最后拆分新旧链表。
| 1 | # Definition for singly-linked list with a random pointer. | 
二刷1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41"""
# Definition for a Node.
class Node(object):
    def __init__(self, val, next, random):
        self.val = val
        self.next = next
        self.random = random
"""
class Solution(object):
    def copyRandomList(self, head):
        """
        :type head: Node
        :rtype: Node
        """
        if not head:
            return head
        
        pre = head
        while pre:
            temp = pre.next
            pre.next = Node(pre.val, None, None)
            pre.next.next = temp
            pre = pre.next.next
        
        pre = head
        while pre:
            if pre.random:
                pre.next.random = pre.random.next
            pre = pre.next.next
        
        res = head.next
        pre = res
        
        while head:
            head.next = head.next.next
            if pre.next:
                pre.next = pre.next.next
            head = head.next
            pre = pre.next
        
        return res
141. 环形链表
题目描述
给定一个链表,判断链表中是否有环。
为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。
示例 1:
输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。
示例 2:
输入:head = [1,2], pos = 0
输出:true
解释:链表中有一个环,其尾部连接到第一个节点。
示例 3:
输入:head = [1], pos = -1
输出:false
解释:链表中没有环。
进阶:
你能用 O(1)(即,常量)内存解决此问题吗?
解题思路
使用快慢指针,如果有环一定相遇。
| 1 | # Definition for singly-linked list. | 
142. 环形链表 II
题目描述
给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。
说明:不允许修改给定的链表。
示例 1:
输入:head = [3,2,0,-4], pos = 1
输出:tail connects to node index 1
解释:链表中有一个环,其尾部连接到第二个节点。
示例 2:
输入:head = [1,2], pos = 0
输出:tail connects to node index 0
解释:链表中有一个环,其尾部连接到第一个节点。
示例 3:
输入:head = [1], pos = -1
输出:no cycle
解释:链表中没有环。
进阶:
你是否可以不用额外空间解决此题?
解题思路
快慢指针,找到换之后,一个指针从头遍历。
| 1 | # Definition for singly-linked list. | 
集合。将访问过的节点保存起来,遍历节点,如果节点在字典中,则说明重复是为环的入口;否则没有环。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution(object):
    def detectCycle(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        if not head or not head.next:
            return None
        
        Dict = set()
        while head:
            if head in Dict:
                return head
            Dict.add(head)
            head = head.next
            
        return None
143. 重排链表
题目描述
给定一个单链表 L:L0→L1→…→Ln-1→Ln ,
将其重新排列后变为: L0→Ln→L1→Ln-1→L2→Ln-2→…
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
示例 1:1
给定链表 1->2->3->4, 重新排列为 1->4->2->3.
示例 2:1
给定链表 1->2->3->4->5, 重新排列为 1->5->2->4->3.
解题思路
- 使用快慢指针先将链表从中间截断为两个链表,如果链表长度为奇数,则第一条链表长度多1;如1,2,3,4,5,拆分为1,2,3和4,5;
- 将第二条链表翻转;即4,5翻转为5,4
- 然后归并合并。
| 1 | # Definition for singly-linked list. | 
147. 对链表进行插入排序
题目描述
对链表进行插入排序。

插入排序的动画演示如上。从第一个元素开始,该链表可以被认为已经部分排序(用黑色表示)。
每次迭代时,从输入数据中移除一个元素(用红色表示),并原地将其插入到已排好序的链表中。
插入排序算法:
- 插入排序是迭代的,每次只移动一个元素,直到所有元素可以形成一个有序的输出列表。
- 每次迭代中,插入排序只从输入数据中移除一个待排序的元素,找到它在序列中适当的位置,并将其插入。
- 重复直到所有输入数据插入完为止。
示例 1:1
2输入: 4->2->1->3
输出: 1->2->3->4
示例 2:1
2输入: -1->5->3->4->0
输出: -1->0->3->4->5
解题思路
如果链表本来就是升序的,则往后遍历;
否则如果一个节点的值小于前一个节点,寻找合适的位置插入。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution(object):
    def insertionSortList(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        if not head or not head.next:
            return head
        
        dummy = ListNode(0)
        dummy.next = head
        cur = head
        while cur.next:
            if cur.val < cur.next.val:
                cur = cur.next
            else:
                pre = dummy
                while pre.next and pre.next.val < cur.next.val:
                    pre = pre.next
                temp = cur.next
                cur.next = temp.next
                temp.next = pre.next
                pre.next = temp
        
        return dummy.next
148. 排序链表
题目描述
在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序。
示例 1:1
2输入: 4->2->1->3
输出: 1->2->3->4
示例 2:1
2输入: -1->5->3->4->0
输出: -1->0->3->4->5
解题思路
归并排序
| 1 | # Definition for singly-linked list. | 
160. 相交链表
题目描述
编写一个程序,找到两个单链表相交的起始节点。
如下面的两个链表:
在节点 c1 开始相交。
示例 1:
1
2
3输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
输出:Reference of the node with value = 8
输入解释:相交节点的值为 8 (注意,如果两个列表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。
示例 2:
| 1 | 输入:intersectVal = 2, listA = [0,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1 | 
示例 3:
| 1 | 输入:intersectVal = 0, listA = [2,6,4], listB = [1,5], skipA = 3, skipB = 2 | 
注意:
- 如果两个链表没有交点,返回 null.
- 在返回结果后,两个链表仍须保持原有的结构。
- 可假定整个链表结构中没有循环。
- 程序尽量满足 O(n) 时间复杂度,且仅用 O(1) 内存。
解题思路
链表拼接
| 1 | # Definition for singly-linked list. | 
第一次遍历,先计算两个链表的长度;
第二次遍历,让长的先走长度差,然后同时移动,判断是否有相同节点。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution(object):
    def getIntersectionNode(self, headA, headB):
        """
        :type head1, head1: ListNode
        :rtype: ListNode
        """
        if not headA or not headB:
            return None
        
        countA = countB = 0
        a, b = headA, headB
        while a:
            a = a.next
            countA += 1
        while b:
            b = b.next
            countB += 1
            
        if countA > countB:
            for i in range(countA-countB):
                headA = headA.next
        else:
            for i in range(countB-countA):
                headB = headB.next
        
        while headA and headB:
            if headA == headB:
                return headA
            headA, headB = headA.next, headB.next
        
        return None
206. 反转链表
题目描述
反转一个单链表。
示例:1
2输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
进阶:
你可以迭代或递归地反转链表。你能否用两种方法解决这道题?
解题思路
迭代1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution(object):
    def reverseList(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        if not head or not head.next:
            return head
        
        dummy = ListNode(0)
        dummy.next = head
        cur = head.next
        head.next = None
        
        while cur:
            temp = cur.next
            cur.next = dummy.next
            dummy.next = cur
            cur = temp
        
        return dummy.next
递归1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution(object):
    def reverseList(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        if not head or not head.next:
            return head
        
        return self.helper(head, ListNode(0))
    
    def helper(self, cur, dummy):
        if not cur:
            return dummy.next
        temp = cur.next
        cur.next = dummy.next
        dummy.next = cur
        cur = temp
        return self.helper(cur, dummy)
234. 回文链表
题目描述
请判断一个链表是否为回文链表。
示例 1:1
2输入: 1->2
输出: false
示例 2:1
2输入: 1->2->2->1
输出: true
进阶:
你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题?
解题思路
| 1 | # Definition for singly-linked list. | 
| 1 | # Definition for singly-linked list. | 
| 1 | # Definition for singly-linked list. | 
 
        