本系列为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. |