目录
206. 反转链表
https://leetcode-cn.com/problems/reverse-linked-list/
反转一个单链表。
示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
进阶:
你可以迭代或递归地反转链表。你能否用两种方法解决这道题?
题解
一:迭代,定义了三个指针,通过挪动三个指针来完成题目。
class Solution(object):
def reverseList(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
pre_node, cur_node = None, head
while cur_node:
next_node = cur_node.next
cur_node.next = pre_node
pre_node = cur_node
cur_node = next_node
return pre_node
二:迭代,copy官方题解,https://leetcode-cn.com/problems/reverse-linked-list/solution/fan-zhuan-lian-biao-by-leetcode/,
递归版本稍微复杂一些,其关键在于反向工作。假设列表的其余部分已经被反转,现在我该如何反转它前面的部分?
假设列表为:
若从节点到已经被反转,而我们正处于。
我们希望的下一个节点指向。所以,也即
要小心的是的下一个必须指向 Ø 。如果你忽略了这一点,你的链表中可能会产生循环。如果使用大小为 2 的链表测试代码,则可能会捕获此错误。函数reverseList返回的是翻转后的链表的头节点,其中head.next=None,是必须的,因为翻转后,原头节点的next是空。
class Solution(object):
def reverseList(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
if not head or not head.next:
return head
next_node = head.next
p = self.reverseList(head.next)
next_node.next = head
head.next = None
return p
92. 反转链表 II
https://leetcode-cn.com/problems/reverse-linked-list-ii/
反转从位置 m 到 n 的链表。请使用一趟扫描完成反转。
说明:1 ≤ m ≤ n ≤ 链表长度。
示例:输入: 1->2->3->4->5->NULL, m = 2, n = 4,输出: 1->4->3->2->5->NULL。
题解
一:借鉴206反转链表的思路,其中reverse函数是翻转m到n之间的链表,并返回翻转之后的头节点pre(4)以及原链表的下一个节点cur(5,即无需翻转的第一个节点),主体结构的cur(2)是第一个要翻转的节点(翻转之后是新链表的尾节点),pre(1)是最后一个无需翻转的节点。
class Solution(object):
def reverseBetween(self, head, m, n):
"""
:type head: ListNode
:type m: int
:type n: int
:rtype: ListNode
"""
def reverse(node):
num = n - m + 1
cnt = 1
pre, cur = None, node
while cnt <= num:
next = cur.next
cur.next = pre
pre = cur
cur = next
cnt += 1
return pre, cur
before_head = ListNode(0)
before_head.next = head
pre, cur = before_head, head
cnt = 1
while cnt < m:
pre = cur
cur = cur.next
cnt += 1
before, next = reverse(cur)
pre.next, cur.next = before, next
return before_head.next
class Solution(object):
def reverseBetween(self, head, m, n):
before_head = ListNode(0)
before_head.next, pre = head, before_head
i, cur = 1, head
while i < m:
pre, cur = cur, cur.next
i += 1
start = cur
l_pre, next = None, None
while i <= n:
next = cur.next
cur.next = l_pre
l_pre, cur = cur, next
i += 1
start.next = cur
pre.next = l_pre
return before_head.next
83. 删除排序链表中的重复元素
https://leetcode-cn.com/problems/remove-duplicates-from-sorted-list/
给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次。
示例 1:输入: 1->1->2,输出: 1->2
示例 2:输入: 1->1->2->3->3,输出: 1->2->3
题解
一:下一个元素与当前重复的元素,让该指针指向下一个元素的下一个(即跳掉下一个元素),若不重复,比较后续元素。因为每个元素只出现一次,头节点就依然会是头节点,不会被删除。最后一个节点单独处理,其next为None。
class Solution(object):
def deleteDuplicates(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
if not head:
return head
pre, cur = head, head.next
while cur:
if pre.val == cur.val:
cur = cur.next
else:
pre.next = cur
pre = cur
pre.next = None
return head
82. 删除排序链表中的重复元素 II
https://leetcode-cn.com/problems/remove-duplicates-from-sorted-list-ii/
给定一个排序链表,删除所有含有重复数字的节点,只保留原始链表中 没有重复出现 的数字。
示例 1:输入: 1->2->3->3->4->4->5,输出: 1->2->5
示例 2:输入: 1->1->1->2->3,输出: 2->3
题解
一:这边与上一题的区别,头节点可能会被删掉,故添加一个虚拟节点,符合要求的链表的最后一个节点是pre,考虑当前节点,他若和前一个节点或者后一个节点相等,都要跳掉,若不相等,则将pre指向该节点,要注意每时每刻符合要求的最后一个节点都是pre,故遍历完毕,要让pre.next=None。
class Solution(object):
def deleteDuplicates(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
if not head or not head.next:
return head
before_head = ListNode(head.val - 1)
before_head.next, pre, cur, l_pre = head, before_head, head, before_head
while cur:
next = cur.next
if l_pre.val != cur.val and (not next or cur.val != next.val):
pre.next = cur
pre = cur
l_pre = cur
cur = next
pre.next = None
return before_head.next
86. 分隔链表
https://leetcode-cn.com/problems/partition-list/
给定一个链表和一个特定值 x,对链表进行分隔,使得所有小于 x 的节点都在大于或等于 x 的节点之前。你应当保留两个分区中每个节点的初始相对位置。
示例:输入: head = 1->4->3->2->5->2, x = 3,输出: 1->2->2->4->3->5
题解
一:创建两个链表(小于是一个,大于等于是一个,在把这俩链表合并成一个),小trick:初始化为两个哑 ListNode,这样可以避免判断是否是第一个节点(小于、大于等于的),注意事项:要注意大于等于x的那个链表的尾节点的next要初始化为空,不然他有可能会指向别的节点,从而形成环。
class Solution(object):
def partition(self, head, x):
"""
:type head: ListNode
:type x: int
:rtype: ListNode
"""
less_head, great_head = ListNode(x), ListNode(x)
cur, cur_less, cur_great = head, less_head, great_head
while cur:
next = cur.next
if cur.val < x:
cur_less.next = cur
cur_less = cur
else:
cur_great.next = cur
cur_great = cur
cur = next
cur_great.next = None
cur_less.next = great_head.next
return less_head.next
328. 奇偶链表
https://leetcode-cn.com/problems/odd-even-linked-list/
给定一个单链表,把所有的奇数节点和偶数节点分别排在一起。请注意,这里的奇数节点和偶数节点指的是节点编号的奇偶性,而不是节点的值的奇偶性。请尝试使用原地算法完成。你的算法的空间复杂度应为 O(1),时间复杂度应为 O(nodes),nodes 为节点总数。
示例 1:输入: 1->2->3->4->5->NULL,输出: 1->3->5->2->4->NULL
示例 2:输入: 2->1->3->5->6->4->7->NULL ,输出: 2->3->6->7->1->5->4->NULL
说明:应当保持奇数节点和偶数节点的相对顺序。链表的第一个节点视为奇数节点,第二个节点视为偶数节点,以此类推。
题解
一:还是两个链表,第一个奇数节点,第二个偶数节点,做这类题目注意把握好循环进行下去的条件,即用那个指针进行判断,可以用例子来看看是否有问题,例如[1,2,3,4]和[1,2,3,4,5]。
这边要注意,循环体中的判断第一处if even_cur.next是为了确保even_cur.next.next这句话的正确性,第二处if odd_cur.next:是为了确保odd_cur不为None,保证odd_cur.next = even_head的正确性。
class Solution(object):
def oddEvenList(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
if not head or not head.next:
return head
odd_head, even_head = head, head.next
odd_cur, even_cur = odd_head, even_head
while even_cur:
odd_cur.next = even_cur.next
if even_cur.next:
even_cur.next = even_cur.next.next
if odd_cur.next:
odd_cur = odd_cur.next
even_cur = even_cur.next
odd_cur.next = even_head
return odd_head
精简一点,在循环的时候一起判断,不再循环体中单独判断。
class Solution(object):
def oddEvenList(self, head):
if not head or not head.next:
return head
odd_head, even_head = head, head.next
odd_cur, even_cur = odd_head, even_head
while even_cur and even_cur.next:
odd_cur.next = even_cur.next
even_cur.next = even_cur.next.next
odd_cur = odd_cur.next
even_cur = even_cur.next
odd_cur.next = even_head
return odd_head
2. 两数相加
https://leetcode-cn.com/problems/add-two-numbers/
给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。您可以假设除了数字 0 之外,这两个数都不会以 0 开头。
示例:输入:(2 -> 4 -> 3) + (5 -> 6 -> 4),输出:7 -> 0 -> 8,原因:342 + 465 = 807
题解
一:没啥注意的,依旧是关注指针是否为None的问题(即我们是否用了None的next,也即合法性)。另外,所有的数加完之后,要判断是否有进位,若有还要创建一个节点以对应该进位。
class Solution(object):
def addTwoNumbers(self, l1, l2):
"""
:type l1: ListNode
:type l2: ListNode
:rtype: ListNode
"""
before_head = ListNode(0)
cur, cur_1, cur_2, carry = before_head, l1, l2, 0
while cur_1 or cur_2:
val = carry
if cur_1:
val += cur_1.val
cur_1 = cur_1.next
if cur_2:
val += cur_2.val
cur_2 = cur_2.next
carry = val // 10
val = val % 10
cur.next = ListNode(val)
cur = cur.next
if carry:
cur.next = ListNode(carry)
return before_head.next
445. 两数相加 II
https://leetcode-cn.com/problems/add-two-numbers-ii/
给你两个 非空 链表来代表两个非负整数。数字最高位位于链表开始位置。它们的每个节点只存储一位数字。将这两数相加会返回一个新的链表。你可以假设除了数字 0 之外,这两个数字都不会以零开头。
进阶:如果输入链表不能修改该如何处理?换句话说,你不能对列表中的节点进行翻转。
示例:输入:(7 -> 2 -> 4 -> 3) + (5 -> 6 -> 4),输出:7 -> 8 -> 0 -> 7
题解
一:反转链表,再用题2的方法,得到结果之后继续反转
二:借助数据结构,将链表中的数据存储下来。这边用的列表。
class Solution(object):
def addTwoNumbers(self, l1, l2):
"""
:type l1: ListNode
:type l2: ListNode
:rtype: ListNode
"""
rec1, rec2, rec = [], [], []
self._abstract_num(l1, rec1)
self._abstract_num(l2, rec2)
self._sum(rec1, rec2, rec)
before_head = ListNode(0)
cur = before_head
for i in range(len(rec)-1, -1, -1):
val = rec[i]
cur.next = ListNode(val)
cur = cur.next
return before_head.next
def _abstract_num(self, l, rec):
cur = l
while cur:
rec.append(cur.val)
cur = cur.next
def _sum(self, rec1, rec2, rec):
i, j, carry = len(rec1)-1, len(rec2)-1, 0
while i >= 0 or j >= 0:
val = carry
if i >= 0:
val += rec1[i]
i -= 1
if j >= 0:
val += rec2[j]
j -= 1
carry = val // 10
val = val % 10
rec.append(val)
if carry:
rec.append(carry)
三:copy官方题解,https://leetcode-cn.com/problems/add-two-numbers-ii/,借用栈的结构后进先出,list的append和pop可做到,然后最后倒着把链表连起来
class Solution(object):
def addTwoNumbers(self, l1, l2):
rec1, rec2 = [], []
self._abstract_num(l1, rec1)
self._abstract_num(l2, rec2)
ans, carry = None, 0
while rec1 or rec2 and carry != 0:
x = rec1.pop() if rec1 else 0
y = rec2.pop() if rec2 else 0
val = carry + x + y
carry = val // 10
val = val % 10
cur = ListNode(val)
cur.next = ans
ans = cur
return ans
def _abstract_num(self, l, rec):
while l:
rec.append(l.val)
l = l.next
203. 移除链表元素
https://leetcode-cn.com/problems/remove-linked-list-elements/
删除链表中等于给定值 val 的所有节点。
示例:输入: 1->2->6->3->4->5->6, val = 6, 输出: 1->2->3->4->5
题解
一:跳过就👌啦,要注意这句话pre.next = None,否则若最后一个元素应该被删除,缺少这句话删不掉,虚拟头节点一直就是链表题目的小trick。
class Solution(object):
def removeElements(self, head, val):
"""
:type head: ListNode
:type val: int
:rtype: ListNode
"""
before_head = ListNode(0)
pre, cur = before_head, head
while cur:
if cur.val != val:
pre.next = cur
pre = cur
cur = cur.next
pre.next = None
return before_head.next
21. 合并两个有序链表
将两个升序链表合并为一个新的升序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例:输入:1->2->4, 1->3->4,输出:1->1->2->3->4->4
题解
一:不改变原先两链表的结构
class Solution(object):
def mergeTwoLists(self, l1, l2):
"""
:type l1: ListNode
:type l2: ListNode
:rtype: ListNode
"""
before_head = ListNode(0)
pre = before_head
while l1 or l2:
if not l1:
pre.next = ListNode(l2.val)
l2 = l2.next
elif not l2:
pre.next = ListNode(l1.val)
l1 = l1.next
elif l1.val < l2.val:
pre.next = ListNode(l1.val)
l1 = l1.next
else:
pre.next = ListNode(l2.val)
l2 = l2.next
pre = pre.next
return before_head.next
二:可以改变原先链表结构
class Solution(object):
def mergeTwoLists(self, l1, l2):
before_head = ListNode(0)
pre = before_head
while l1 and l2:
if l1.val < l2.val:
pre.next = l1
l1 = l1.next
else:
pre.next = l2
l2 = l2.next
pre = pre.next
pre.next = l1 if l1 else l2
return before_head.next